1 定义函数
在scala中定义函数,需要定义函数的函数名、参数、函数体
scala要求必须给出所有参数的类型,但是不一定给出函数返回值的类型,只要右侧的函数体中不包含递归语句,scala就可以自己根据右侧的表达式推断类出返回类型。
scala> :paste
// Entering paste mode (ctrl-D to finish)
def sayhello(name:String,age:Int) = {
if(age >= 18){
printf("Hi,%s,you are a big boy",name)
println()
age
}else{
printf("Hi,%s,you are a little boy",name)
println()
age
}
}
// Exiting paste mode, now interpreting.
sayhello: (name: String, age: Int)Int
scala> sayhello("Leo",21)
Hi,Leo,you are a big boy
res5: Int = 21
scala>
2 在代码块中定义函数体
单行的函数
scala> def sayhello(name : String) = printf("Hello,%s",name)
sayhello: (name: String)Unit
scala> sayhello("Leo")
Hello,Leo
scala>
如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值。
scala> :paste
// Entering paste mode (ctrl-D to finish)
def sum(n:Int) = {
var result = 0
for (i <- 1 to n){
result += i
}
result
}
// Exiting paste mode, now interpreting.
sum: (n: Int)Int
scala> sum(4)
res16: Int = 10
scala>
3 递归函数
如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型。
例如:实现经典的斐波那契数列:
10
9 + 8
8 + 7+7+6
7+6+6+5+6+5+5+4--------
scala> :paste
// Entering paste mode (ctrl-D to finish)
def fab(n : Int): Int = {
if(n <= 0) 1
else fab(n - 1) + fab(n - 2)
}
// Exiting paste mode, now interpreting.
fab: (n: Int)Int
scala> fab(10)
res17: Int = 144
4 默认参数
在scala中,有时我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值,此时就定义在定义函数的时使用默认参数。
如果给出的参数不够,则会从左往右依次应用参数。
scala> :paste
// Entering paste mode (ctrl-D to finish)
def sayhello(name:String,age : Int = 20){
print("Hello, "+name+",your age is "+age)
}
// Exiting paste mode, now interpreting.
sayhello: (name: String, age: Int)Unit
scala> sayhello("Leo")
Hello, Leo,your age is 20
scala> sayhello("Leo",30)
Hello, Leo,your age is 30
scala>
5 带名参数
在调用函数时,也可以按不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递。
还可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数前面
scala> sayhello(age=10,name="Leo")
Hello, Leo,your age is 10
#混合使用
scala> :paste
// Entering paste mode (ctrl-D to finish)
def sayhello(firstname : String,middlename : String,lastname: String) = {
print(firstname + " "+ middlename + " "+ lastname)
}
// Exiting paste mode, now interpreting.
sayhello: (firstname: String, middlename: String, lastname: String)Unit
scala> sayhello("Leo",lastname="Jack",middlename="Tem")
Leo Tem Jack
scala>
6 变长参数
在scala中,有时我们需要将函数定义为参数个数可变的形式,则此时可以使用变长参数定义函数。
scala> :paste
// Entering paste mode (ctrl-D to finish)
def sum(nums : Int*) = {
var result = 0
for (num <- nums){
result += num
}
result
}
// Exiting paste mode, now interpreting.
sum: (nums: Int*)Int
scala> sum(1,2,3)
res32: Int = 6
scala>
7 使用序列调用变长参数
在如果想要讲一个已有的序列直接调用变长参数函数,是不对的。如下
scala> 1 to 5
res33: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)
scala> 1.to(5)
res34: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)
scala> sum(1 to 5)
<console>:13: error: type mismatch;
found : scala.collection.immutable.Range.Inclusive
required: Int
sum(1 to 5)
^
scala>
此时需要使用scala特殊的语法将参数定义为序列,让scala解释器能够识别。这种语法非常有用!一定要好好注意,在spark的源码中大量使用到了。
scala> sum(1 to 3:_*)
res36: Int = 6
案例:使用递归函数实现累加
scala> def sum2(nums:Int*):Int={
| if(nums.length == 0) 0
| else nums.head + sum2(nums.tail:_*)
| }
sum2: (nums: Int*)Int
scala> sum2(1,2,3,4)
res38: Int = 10
8 过程
在scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Until。这样的函数被称之为过程。过程通常用于不需要返回值的函数。
过程还有一种写法,就是函数的返回值类型定义为Until
#这是不是过程
scala> def sayhello(name : String) = "Hello," + name
sayhello: (name: String)String
#这个是过程
scala> def sayhello(name:String){print("Hello,"+name)}
sayhello: (name: String)Unit
scala> sayhello("Leo")
Hello,Leo
scala> def sayhello(name : String) = "Hello," + name
sayhello: (name: String)String
scala> sayhello("Leo")
res40: String = Hello,Leo
#这个是过程
scala> def sayhello(name : String):Unit = "Hello," + name
sayhello: (name: String)Unit
scala> sayhello("Leo")
9 lazy值
在scala中,提供了lazy值的特性,也就是说,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等。
scala> import scala.io.Source._
import scala.io.Source._
scala> lazy val lines = fromFile("C://Users//zhu//Desktop//test.txt").mkString
lines: String = <lazy>
scala> print(lines)
Hello world
scala> lazy val lines = fromFile("C://Users//zhu//Desktop//test1.txt").mkString
lines: String = <lazy>
scala> print(lines)
java.io.FileNotFoundException: C:\Users\zhu\Desktop\test1.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:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
at .lines$lzycompute(<console>:14)
at .lines(<console>:14)
... 32 elided
scala> val lines = fromFile("C://Users//zhu//Desktop//test1.txt").mkString
java.io.FileNotFoundException: C:\Users\zhu\Desktop\test1.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:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
... 32 elided
scala> def getlines = fromFile("C://Users//zhu//Desktop//test1.txt").mkString
getlines: String
scala> getlines
java.io.FileNotFoundException: C:\Users\zhu\Desktop\test1.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:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
at .getlines(<console>:14)
... 32 elided
scala>
10 异常
在scala中,异常处理和捕获机制与java中是很类似的
# 1
scala> :paste
// Entering paste mode (ctrl-D to finish)
try{
throw new IllegalArgumentException("Illegal argument!!!")
}catch{
case _: IllegalArgumentException => print("sorry,error!!!")
}finally{
print("release io resource!!!")
}
// Exiting paste mode, now interpreting.
sorry,error!!!release io resource!!!
# 2 没有catch成功
scala> import java.io._
import java.io._
scala> :paste
// Entering paste mode (ctrl-D to finish)
try{
throw new IOException("io exception!!!")
}catch{
case _: IllegalArgumentException => print("illegal argement!!!")
}
// Exiting paste mode, now interpreting.
java.io.IOException: io exception!!!
at .liftedTree1$1(<console>:16)
... 37 elided
# 3 catch成功
scala> :paste
// Entering paste mode (ctrl-D to finish)
try{
throw new IOException("user defined exception")
}catch{
case e1:IllegalArgumentException => println("illegal argument!!")
case e2:IOException => println("io exception")
}
// Exiting paste mode, now interpreting.
io exception
scala>