一、for循环的进阶实战
1.for循环的变量可以有多个
for(i <- 1 to 2; j <- 1 to 3) println(i +" " + j )
这个for循环输出:1 1
1 2
1 3
2 1
2 2
2 3
1.<-往左的箭头符号表示i会接受1 to 2这个集合里的值。每次循环集合的时候,把每次循环的元素赋值给i和j.
2.i和j不需要声明类型。scala会根据右侧的集合中具体元素的类型来自动进行类型推导。类型推导是scala中非常强大的内容。2.for循环的条件守卫
for(i <- 1 to 2; j <- 1 to 3 if i != j) println(i +" " + j )
这个for循环输出:
1 2
1 3
2 1
2 3
我们可以在for循环的表达式里加入条件判断等。叫条件表达式的守卫。这种方式在spark中非常常见的。在正常的scala编程中也非常常见。当然条件表达式可以很复杂。
以上就是for循环相对进阶的部分,条件表达式的守卫比较重要。scala对开发的计算数据而言,提供了非常多的方便。
二、function的进阶实战
1.函数是有值的 Vs 匿名函数
def addA(x : Int) = x + 100
val add = (x : Int) => x + 200
println(addA(2) + " " + add(5))
输出:
102 205
main方法不要求返回值时,返回Unit,也就是空值。函数有值的,如果不返回什么值,它就是空值。
所以,我们定义函数的时候,addA函数的参数是一个整数,函数是有值的,所以函数一般都会有个=,=右侧就是怎么对这个函数进行计算。传入x,返回的计算结果就是对x加100.
函数有值是scala中非常非常重要的特点,因为函数是有值的,每个函数执行的时候必然有一个结果,所以,函数可以作为函数的参数去传递。这个特点衍生了函数式编程中很多重要的技巧。实际上,我们进行一些复杂的算法的时候,根本不需要为函数命名。
val add = (x : Int) => x + 200
常量add 函数部分 ( 注意括号后面是箭头=>)匿名函数是函数常见的一种状态,因为我们一般关心的是函数本身怎么做这件事情,对函数名字一般不关心。通过add这个常量的名称以及在其后加个括号,传入参数来调用。
2.递归函数必须要声明返回值类型
上面addA函数并没有声明返回值,是因为scala编译器会根据右侧的表达式自动推断出函数的返回值。例如可以推断出addA返回值是整数。大多数情况下,都不需要声明函数的返回值类型,但是有一种特殊情况:递归调用。
def fac(n : Int) : Int = if(n <= 0) 1 else n * fac(n-1)
println(fac(9))
递归调用在scala以外的其他的系统或者框架的实现中,也可以不用声明函数的返回值。但是在scala中,必须指明递归调用函数的返回值。因为如果不指明递归调用函数的返回值的话,编译器会报错。
3.默认参数
def combine(content : String , left : String = "[", right : String = "]") = left + content + right
println(combine("I love spark!"))
println(combine("I love spark!", "<<"))
输出:
[I love spark!]
<<I love spark!]
我们可以给函数参数提供默认值。如果传入第二个参数,肯定就会用我们传入的值覆盖掉原来默认的值。
4.函数的参数是可变的
def connected(args : Int*) = {
var result = 0
for(arg <- args) result += arg
result
}
println(connected(1,2,3,4,5))
println(connected(1,2,3,4,5,6))
输出:
15
21
函数的参数可以输入多个,输入5个结果是15,输入6个结果是21.
以上就是从写代码的角度讲,函数常见的一些形态。
三、lazy的使用
lazy val file = Source.fromFile("E:\\ni.txt")
for(line <- file.getLines) println(line)
文件名不对,运行会报错
Exception in thread "main" java.io.FileNotFoundException: E:\ni.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:90)
at scala.io.Source$.fromFile(Source.scala:75)
at scala.io.Source$.fromFile(Source.scala:53)
at com.dt.scala.hello.ForFunctionLazy$.main(ForFunctionLazy.scala:35)
at com.dt.scala.hello.ForFunctionLazy.main(ForFunctionLazy.scala)
但是如果注释掉下面一行
lazy val file = Source.fromFile("E:\\ni.txt")
println("scala")
//for(line <- file.getLines) println(line)
输出:scala
说明第一句和第二句都执行了,并没有报错。如果去掉lazy就报错了。说明变量或者常量加上lazy修饰,只有在第一次使用时,才会被实例化。
懒执行在数据处理方面,尤其对于同一个数据有很多迭代步骤的计算是非常重要的。因为延迟执行,我们可以看到更多的执行步骤,当你能看到一个计算的更多步骤时,进行优化的范围也就更大,优化力度也就会更好。而在spark大数据计算中,充分利用了这一点,lazy级别。
以上就是今天的内容,如果没有接触过scala,勉励大家把每个例子重复7次,基础就会很扎实,不要眼高手低,试一试就知道重复7次的效果了。感恩!
参考资料来源于 DT大数据梦工厂 Scala零基础实战经典第4课 由王家林老师讲解