记录一下自己开始学习Scala的基础语法,以后便于自己查阅。
基础部分
变量声明 var n = 9
输入 line = readLine()
do…while() 循环示例:
var line = ""
do {
println("Please input some words blow......")
line = readLine()
println("Read: " + line)
} while (line != "")def doWhile() 函数定义
def doWhile(){
var line = ""
do {
line = readLine()
println("Read: " + line)
} while (line != "")
}**if表达式 **
val spark = 7
if(spark>=5) "adult" else "child"结果 String = adult
在Scala中的if表达式是有值的,但Java中是没有的。
Scala中object的理解:
object作为Scala中的一个关键字,相当于Java中的public static class这样的一个修饰符,也就是说object中的成员都是静态的,事实上object是Scala中的静态类,不是对象。object中的内容class都可以在没有实例的时候直接去调用。object中的apply方法是class对象生成的工厂方法,用于控制对象的生成;
object HelloOOP {
def main(arg:Array[String]) :Unit = {
val HelloOOP = HelloOOP()
HelloOOP.sayHello
}
def apply():HelloOOP = {
new HelloOOP
}
}变量声明为lazy:
表示这个变量只有在第一次使用时,才会发生计算,比如说打开文件,打开数据库,操作网络
object LazyOps {
def main(args: Array[String]): Unit = {
lazy val file = Source.fromFile("E:\\SparkWangJialin.txt")
println("Scala")
for (line <- file.getLines) println(line)
}
}try…catch…finally的使用 首先尝试完成try中的操作 ,RuntimeException中定义要错误的提示语,在catch中可以用e.getMessage()接收RuntimeException的内容。
val n = 99
try {
if (n % 2 == 0) n /2 else throw
new RuntimeException("N must be event")
// Use the file
}catch {
case e : Exception => println("The exception is :" + e.getMessage())
}finally{
println(n)
}程序运行结果 The exception is:N must be double 99 for循环
for (i <- 1 to 10) {
println("Number is :" + i)
}数组 ** 定长数组(Array) 变长数组(Arraybuffer)
**不可变数组声明 var z = new Array[Int](3)
创建不可变数组 val arr1 = Array(1,3,5)
访问数组元素的值 arr1(2) //访问数组元素第三个值
修改数组元素的值 arr1(2) = 8
数组遍历
var total = 0.0
for (i <-0 to (arr1.length -1)) {
total += arr1 //计算总和
}
var max = arr1(0);
for(i <- 1 to (arr1.length -1) ) {
if (arr1(i) > max) max =arr1(i)
}创建可变数组 –可对数组元素增添或删减元素
首先导入包 import scala.collection.mutable.ArrayBuffer
val b = ArrayBuffer[Int]()
b += 1 //追加元素 内容为1
b += (1, 2, 3, 5) //内容为 (1, 1, 2, 3, 5)
b ++= Array(8, 13, 21) //在现有的b的后面追加8, 13, 21 三个元素 (1, 1, 2, 3, 5, 8, 13, 21)
b.trimEnd(5) //删除b后面的5个元素 结果为(1, 1, 2)
b.insert(2, 6) //下标为2元素增加元素6,后面的元素后移 结果为 (1, 1, 6, 2)
b.insert(2, 7, 8, 9) 在下标为2元素位置插入(7,8,9)结果为 (1, 1, 7, 8, 9, 6, 2)
b.remove(2) //删除下标为2元素 (1, 1, 8, 9, 6, 2)
b.remove(2, 3) //删除下标为2元素开始的三个元素,包括下标为2元素 (1, 1, 2)
b.toArray数组求和:arrBuffer.sum
数组求最大值:arrBuffer.max
数组排序:scala.util.Sorting.quickSort(arrBuffer)
Map和Tuple
1. Map
val map = Map("book"->10,"gun"->18,"ipad"->1000)
默认情况下Map构造的是不可变集合,里面的内容不可修改,若要修改器内容,应:
val scores = scala.collection.mutable.Map("Scala" -> 7, "Hadoop" -> 8, "Spark" -> 10 )
此时为可修改的
scores("Spark"->15)
Map中if…elae的变形
val hadoopScore = scores.getOrElse("Hadoop", 0)
表示如果这个scores中有Hadoop则取出它的值,如果没有,值就为0。 整体实例如下
//不可变集合
val map = Map("book"->10,"gun"->18,"ipad"->1000)
for((k,v) <- map) yield (k,v * 0.9)
//可变集合
val scores = scala.collection.mutable.Map("Scala" -> 7, "Hadoop" -> 8, "Spark" -> 10 )
val hadoopScore = scores.getOrElse("Hadoop", 0)
scores += ("R" -> 9)
scores -= "Hadoop"map()是将函数用于RDD中的每个元素,将返回值构成新的RDD。 原RDD中的元素经map处理后只能生成一个元素
flatmap()是将函数应用于RDD中的每个元素,将返回的迭代器的所有内容构成新的RDD,这样就得到了一个由各列表中的元素组成的RDD,而不是一个列表组成的RDD。原RDD中的元素经flatmap处理后可生成多个元素来构建新RDD。
val b = a.flatMap(x => 1 to x)
根据a中的每个元素的值从1开始每次累加1,直到等于该元素值,生成列表。例如:元素是1,列表是1;元素是2,列表是1、2;
scala> val a = sc.parallelize(1 to 4, 2)
scala> val b = a.flatMap(x => 1 to x)
scala> b.collect
res12: Array[Int] = Array(1, 1, 2, 1, 2, 3, 1, 2, 3, 4) 2. Tuple
Tuple元组可以包含不同类型的元素,例如val tuple =(1,2,3.14,"Rocky","Spark")
Tuple的访问 val third = tuple._3 结果为3.14,其访问下标是从1开始的
数组操作合集
初始集合的每个元素做一次翻倍
val c = Array(2, 3, 5, 7, 11)
//> c : Array[Int] = Array(2, 3, 5, 7, 11)
val result = for (elem <- c) yield 2 * elem
//> result : Array[Int] = Array(4, 6, 10, 14, 22) for 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。Scala 中 for 循环是有返回值的。如果被循环的是 Map,返回的就是 Map,被循环的是 List,返回的就是 List,以此类推。 分步结果展示,更好解释了yield
scala> val c = Array(2,3,5,7,11)
c: Array[Int] = Array(2, 3, 5, 7, 11)
scala> for (elem <- c if elem % 2 == 0) yield 2 * elem
res5: Array[Int] = Array(4)
scala> c.filter(_ % 2 == 0).map(2 * _)
res6: Array[Int] = Array(4)
//filter方法返回了所有使假设条件(_ % 2 == 0)为真的结果,
scala> c.filter(_ % 2 == 0)
res7: Array[Int] = Array(2)
scala> for (i <- 1 to 4) yield i * 2
res8: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8)对数组中的内容做格式处理
scala> val arr = Array(1,7,9)
arr: Array[Int] = Array(1, 7, 9)
scala> arr.mkString(" and ")
res9: String = 1 and 7 and 9
scala> arr.mkString("<",",",">")
res10: String = <1,7,9>对二维数组的声明
val matrix = Array.ofDim[Double](3,4)
matrix: Array[Array[Double]] = Array(Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0, 0.0))可直接赋值matrix(2)(3) = 5
指明数组内元素类型定长
val triangle = new Array[Array[Int]](10)
triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)范型
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?答案是可以使用范型。可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
泛型的定义列表用[]包含,用,分隔,卸载类名之后,构造函数参数列表之前,泛型的具体名称可以任意定义。
1.Scala中类的范型
class Pair[K, V] (val key: K, val value: V)
class Triple[F: ClassTag, S, T](val first: F, val second: S, val third: T)
其中ClassTage[T]解释:
在泛型中,type T是被擦除的。这个是非常有用的,在我们构建数组的时候,但是数组的类型我们也不知道,编译的时候不知道,但是运行的时候要知道,ClassTag只包含实际运行时的类的类型。
val triple = new Triple("PI", 4, 3.1415)
val bigData = new Triple[String, String, Char]("Spark", "Hadoop", 'R')
如在第一行中传入PI根据类型推到可以指定T是String类型,val triple: Triple[String, Int, Double] 这时候ClassTag就可以把String类型这个信息传递给编译器。ClassTag运行时指定在编译的时候无法指定的类型信息。
def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
mkArray(42, 13).foreach(println)
mkArray("Japan","Brazil","Germany").foreach(println)
结果为:
42
13
Japan
Brazil
Germany2. 方法的范型
写法是在方法名后面加上泛型列表
//getData函数传入泛型为T的运行时List类型参数,返回list.length / 2的整数。
def getData[T](list:List[T]) = list(list.length / 2)
// List索引从0开始,执行结果:Hadoop
println(getData(List("Spark","Hadoop",'R')));
// 获得getData函数引用
val f = getData[Int] _
// 调用getData函数,执行结果:4
println(f(List(1,2,3,4,5,6)));
def position[T](list: List[T], value: T): Int = {
list.indexOf(value) //取xs的索引
}
position(List(1,2,3), 3) // 结果为2
position(List("one", "two", "three"), "two") // 结果为13.上限和下限
<:泛型类型限定符,表示只限定Comparable子类
Comparable[T]: 为T下界, T: 为Comparable[T]上界
写法为:
[T <: AnyRef]
通配符形式
[_ <: AnyRef] JAVA版的有界类型函数
public class MaximumTest
{
// 比较三个值并返回最大值
public static <T extends Comparable<T>> T maximum(T x, T y, T z)
{
T max = x; // 假设x是初始最大值
if ( y.compareTo( max ) > 0 ){
max = y; //y 更大
}
if ( z.compareTo( max ) > 0 ){
max = z; // 现在 z 更大
}
return max; // 返回最大对象
}
public static void main( String args[] )
{
System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
3, 4, 5, maximum( 3, 4, 5 ) );
System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
"apple", "orange", maximum( "pear", "apple", "orange" ) );
}
}Scala版有界类型函数
class Pair[T <: Comparable[T]](val first: T, val second: T) {
// compareTo方法进行比较,如果大于0返回first
def bigger = if (first.compareTo(second) > 0) first else second
}
object TypeVariablesBounds {
def main(args: Array[String]): Unit = {
// 函数调用
var pair = new Pair("Spark", "Hadoop")
// 执行结果:Spark
println(pair.bigger)
val pair = new Pair_Ordering(3, 5)
println(pairInt.bigger)
}
} 4.Mainfest上下文界定
在scala中数组必须是有类型的,如果直接是泛型的话将会报错,这时候引入了Manifest上下文界定,需要一个Mainfest[T]对象,而mainifest[T]有一个隐式值。 array在创建的时候,编译器仅仅只是创建,并没有指定类型。 数组在定义时必须知道具体的类型,所以在声明方法时,需要添加Manifest
def arrayMake[T : Manifest](first : T, second : T) = {
val r = new Array[T](2); r(0) = first; r(1) = second; r
}
arrayMake(1,2).foreach(println)
结果为 1 25.视图界定
视图界定: 把T类型的实例转换成Comparable[T]类型,如果T类型的实例不是Comparable[T]的子类,利用视图界定的形式就可以把T类型,隐式转换,用于一个操作符要读取一个对象而不是修改一个对象的时候。
功能类似于:
scala> implicit def strToInt(x: String) = x.toInt
strToInt: (x: String)Int
scala> "123"
res0: java.lang.String = 123
scala> val y: Int = "123"
y: Int = 123
scala> math.max("123", 111)
res1: Int = 123在视图界定中可以通过<%定义,表示A应被视为Int型
scala> class Container[A <% Int] { def addIt(x: A) = 123 + x }
defined class Container
scala> (new Container[String]).addIt("123")
res11: Int = 246
scala> (new Container[Int]).addIt(123)
res12: Int = 246
scala> (new Container[Float]).addIt(123.2F)
<console>:8: error: could not find implicit value for evidence parameter of type (Float) => Int
(new Container[Float]).addIt(123.2)
^还有一些其它的操作符(在Scala 2.10前有效)
A =:= B A must be equal to B
A <:< B A must be a subtype of B
A <%< B A must be viewable as B
使用范例如下:
scala> class Container[A](value: A) { def addIt(implicit evidence: A =:= Int) = 123 + value }
defined class Container
scala> (new Container(123)).addIt
res11: Int = 246
scala> (new Container("123")).addIt
<console>:10: error: could not find implicit value for parameter evidence: =:=[java.lang.String,Int]下面的例子中使用了<:<
def manif[T](x: List[T])(implicit m: Manifest[T]) = {
if (m <:< manifest[String])
println("List strings")
else
println("Some other type")
}
manif(List("Spark", "Hadoop"))
manif(List(1, 2))
manif(List("Scala", 3))
结果为:
List strings
Some other type
Some other type