Spark学习(5)——scala函数入门
定义函数
在scala中定义函数时,需要定义函数的函数名、参数、函数体。
例如:
def sayHello(name : String,age: Int) ={
If(age >18){print(“you are a big boy:”+name); age}
else{ print(“you are a little boy:”+name);age}
}
Scala 中要求必须给出所有参数的类型,但是不一定给出函数返回值得类型,只要右侧的函数体中不包含递归的语句,scala就可以自己根据右侧的表达式推断出返回类型
在代码块中定义函数体
单行的函数:def sayHello(name: String) = println(“Hello:”+name)
如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值,与Java中不同,不是使用return 返回值的,例如,下面的函数,实现累加的功能
def Sum(n: Int)={
var sum = 0
for(I <- 1 to n) sum+=i
sum
}
递归函数与返回类型
如果在函数体内递归调用自身,则必须手动给出函数的返回类型
例如:
9+8,8+7+7+6,7+6+6+5+6+5+5+4….
def fab(n: Int) : Int ={
If(n<=1) 1
else fab(n-1)+fab(n-2)
}
默认参数
在scala中,有时我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值,此时就定义在定义函数时使用默认参数
例如:
def sayHello(firstName :String,middleName: String =“tom”,lastName: String =“che”) =firstName + “:”+middleName+”:”+lastName
如果给出的参数不够,则会从左往右依次应用参数
带名参数
在调用函数时也可以不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递
例如上篇提到的sayHello函数可以这样调用
sayHello(firstName=“Mick”,lastName=“Tome”,middleName=“Jack”)
还可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数前面。
例如:
sayHello(“mick”,lastName=“chen”,middleName=“he”)
变长参数
在scala中,有时我们需要将函数定义为参数个数可变的形式,则此时可以用变长参数定义函数。
def sum(sums: Int*)={
var res =0
for(num <- sums)
res +=num
res
}
使用序列调用变长参数
如果想用一个已有的序列直接调用变长参数函数是不对的,比如 val s =sum(1 to 5) .
此时需要使用scala的特殊语法将参数定义为序列,让scala的解释器能够识别,这种语法
非常有用,在Spark源码中大量使用。
例如:
Val s = sum(1 to 5: _*)
案例:使用递归函数实现累加
def sum2(nums: Int*) : Int ={
If(nums.length ==0) 0
else nums.head +sum2(nums.tail: _*)
}
Nums.head取第一个数
Nums.tail 取除去第一个数剩余的数
过程
在scala中,定义函数时,如果函数体直接包裹在花括号里面,而没有使用=连接,
则函数的返回值类型就是Unit,这样的函数就被称之为过程,过程通常用于不需要
返回值的函数。
过程还有一种写法就是把函数的返回值类型定义为Unit
1,不加等号:def sayHello (name:String) {print(“hello world”)}
2,加上返回值Unit:def sayHello(name:String): Unit=“Hello”+name
3,函数:def sayHello(name:String) =“Hello:”+name
lazy值
在scala中,提供了lazy值得特性,也就是说,如果将一个变量声明为lazy
则只有在第一次使用该变量时,变量对用的表达式才会发生计算,
这种计算对于特别耗时的计算操作特别有用,比如,打开文件进行I/o,进行网络I/o等
Import scala.io.Source._
即使文件不存在,也不会报错,只有第一个使用变量时会报错,证明了表达式计算的lazy特性
异常
在scala中,异常处理和捕获机制谁和Java非常类似的