8.3 Scala函数定义和参数传递
1、默认参数。
Scala 可以为函数参数指定默认参数值。如果在调用函数的过程中可以不传递参数,这时函数就会调用它的默认参数值;如果传递了参数,则传递值会取代默认值。
在paste模式下,键入以下内容:
1. def addInt( a:Int=5, b:Int=7 ) : Int = { 2. var sum:Int = 0 3. sum = a + b 4. sum 5. } 6. println( "返回值 : " + addInt() );
按下Ctrl+D,执行以上代码。输出结果如下:
返回值 : 12
2、命名参数。
通常情况下,调用函数时,参数传入和函数定义时参数列表一一对应。
在paste模式下,键入以下内容:
1. def speed(distance: Float, time:Float) :Float = distance/time 2. speed(100,10)
按下Ctrl+D,执行以上代码。输出结果如下:
Float = 10.0
而使用命名参数则允许我们使用任意顺序传入参数。在paste模式下,键入以下内容:
1. speed(time=10,distance=100) 2. speed(distance=100,time=10)
按下Ctrl+D,执行以上代码。输出结果如下:
Float = 10.0
3、变长参数。
Scala在定义函数时允许指定最后一个参数可以重复(变长参数),从而允许函数调用者使用变长参数列表来调用该函数,Scala中使用”*”来指明该参数为重复参数。
在paste模式下,键入以下内容:
1. def echo (args: String *) = for (arg <- args) println(arg) 2. echo ("One") 3. echo ("Hello","World")
按下Ctrl+D,执行以上代码。输出结果如下:
One Hello World
8.4 Scala常用集合
1、数组。
定长数组,就是长度不变的数组,在Scala中使用Array进行声明。
在paste模式下,键入以下内容:
1. var arr = Array(1, 3, 2, 4) 2. 3. //求和 4. println(arr.sum) 5. 6. //最大值 7. println(arr.max) 8. 9. //最小值 10. println(arr.min) 11. 12. //转化成字符串 13. println(arr.mkString("|")) 14. 15. //按大小排序 16. println(arr.sorted.toBuffer) 17. 18. //数组倒序 19. println(arr.reverse.toBuffer) 20. 21. // 将数组(元素是元组类型)转换为Map 22. println(Array(("cn", "china"), ("fr", "french")).toMap)
按下Ctrl+D,执行以上代码。输出结果如下:
10 4 1 1|3|2|4 ArrayBuffer(1, 2, 3, 4) ArrayBuffer(4, 2, 3, 1) Map(cn -> china, fr -> french)
不定长数组,就是长度可变的数组,在Scala中使用ArrayBuffer进行声明。
在paste模式下,键入以下内容:
1. import scala.collection.mutable.ArrayBuffer 2. 3. var arrbuffer = ArrayBuffer(1, 5, 3, 7) 4. 5. //求和 6. println(arrbuffer.sum) 7. 8. //最大值 9. println(arrbuffer.max) 10. 11. //最小值 12. println(arrbuffer.min) 13. 14. //转化成字符串 15. println(arrbuffer.mkString("|")) 16. 17. //按大小排序(由小到大) 18. println(arrbuffer.sorted.toBuffer) 19. 20. //按大小排序(由大到小) 21. println(arrbuffer.sorted.reverse.toBuffer) 22. 23. //数组倒序 24. println(arrbuffer.reverse.toBuffer) 25. 26. // 将数组(元素是元组类型)转换为Map 27. println(Array(("cn", "china"), ("fr", "french")).toMap) 28. 29. // 增加一个元素 30. arrbuffer += 20 31. println(arrbuffer) 32. 33. // 增加一个数组集合 34. arrbuffer ++= Array(50, 60) 35. println(arrbuffer) 36. 37. // 删除最后 3 个元素 38. arrbuffer.trimEnd(3) 39. println(arrbuffer) 40. 41. // 在索引2处插入两个元素 42. arrbuffer.insert(2, 28, 29) 43. println(arrbuffer) 44. 45. // 在索引2处删除三个元素 46. arrbuffer.remove(2, 3) 47. println(arrbuffer) 48. 49. // 清空数组 50. arrbuffer.clear() 51. println(arrbuffer)
按下Ctrl+D,执行以上代码。输出结果如下:
16 7 1 1|5|3|7 ArrayBuffer(1, 3, 5, 7) ArrayBuffer(7, 3, 5, 1) Map(cn -> china, fr -> french) ArrayBuffer(1, 5, 3, 7, 20) ArrayBuffer(1, 5, 3, 7, 20, 50, 60) ArrayBuffer(1, 5, 3, 7) ArrayBuffer(1, 5, 28, 29, 3, 7) ArrayBuffer(1, 5, 7) ArrayBuffer()
数组遍历。
在paste模式下,键入以下内容:
1. val intValueArr2 = Array(0,1,2); 2. //遍历 3. for(i <- intValueArr2) println(i);
;按下Ctrl+D,执行以上代码。输出结果如下:
0 1 2
2、列表。
在Scala中,列表分为不可变的和可变的。不可变列表的实现类为List,可变数组的实现类为ListBuffer。
在paste模式下,键入以下代码:
1. val intList = List(1,2,3) 2. val intListOther = 0::intList
按下Ctrl+D,执行以上代码。输出结果如下:
intList: List[Int] = List(1, 2, 3) intListOther: List[Int] = List(0, 1, 2, 3)
注意,上面操作执行后,intList不会发生变化,依然是List(1,2,3),intListOther是一个新的列表List(0,1,2,3)
列表有头部和尾部的概念,可以使用intList.head来获取上面定义的列表的头部,值是1,使用intList.tail来获取上面定义的列表的尾部,值是List(2,3),可以看出,头部是一个元素,而尾部则仍然是一个列表。
由于列表的头部是一个元素,所以,我们可以使用::操作,在列表的头部增加新的元素,得到一个新的列表。::操作符是右结合的,因此,如果要构建一个列表List(1,2,3),实际上也可以采用下面的方式:
1. val intList = 3::2::1::Nil
执行结果如下:
intList: List[Int] = List(3, 2, 1)
上面代码中,Nil表示空列表。
我们也可以使用:::操作符对不同的列表进行连接得到新的列表。例如,在paste模式下,键入以下内容:
1. val intList1 = List(1,2) 2. val intList2 = List(3,4) 3. val intList3 = intList1:::intList2
按下Ctrl+D,执行以上代码。输出结果如下:
intList1: List[Int] = List(1, 2) intList2: List[Int] = List(3, 4) intList3: List[Int] = List(1, 2, 3, 4)
注意,执行上面操作后,intList1和intList2依然存在,intList3是一个全新的列表。
实际上,Scala还为列表提供了一些常用的方法,比如,如果要实现求和,可以直接调用sum方法,如下:
1. intList.sum
如果要遍历列表,可以使用for循环。例如,在paste模式下,键入以下代码:
1. val intList = List(1,2,3) 2. 3. //遍历 4. for(i <- intList) println(i);
按下Ctrl+D,执行以上代码。输出结果如下:
1 2 3
3、元组。
元组是不同类型的值的聚集。元组和列表不同,列表中各个元素必须是相同类型,而元组可以包含不同类型的元素。
下面我们声明一个名称为tuple的元组。在paste模式下,键入以下代码:
1. val tuple = ("西普",666,666,666); 2. 3. println("我是"+tuple._1); 4. println("我还是"+tuple._2); 5. println(tuple._1+tuple._3);
按下Ctrl+D,执行以上代码。输出结果如下:
我是西普 我还是666 西普666
从上述代码的执行效果可以看出,我们声明一个元组是很简单的,只需要用圆括号把多个元组的元素包围起来就可以了。
当需要访问元组中的某个元素的值时,可以通过类似tuple._1、tuple._2、tuple._3这种方式就可以实现。
4、映射。
在Scala中,映射(Map)是一系列键值对的集合,也就是,建立了键和值之间的对应关系。在映射中,所有的值,都可以通过键来获取。
映射包括可变和不可变两种,默认情况下创建的是不可变映射,如果需要创建可变映射,需要引入scala.collection.mutable.Map包。
下面我们创建一个不可变映射:
1. val university = Map("xipu" -> "xi pu jiao yu", "THU" -> "Tsinghua University","PKU"->"Peking University")
执行以上代码。输出结果如下:
university: scala.collection.immutable.Map[String,String] = Map(XMU -> Xiamen University, THU -> Tsinghua University, PKU -> Peking University)
如果要获取映射中的值,可以通过键来获取。代码如下:
1. println(university("xipu"))
执行以上代码。输出结果如下:
xi pu jiao yu
上面代码通过”xipu”这个键,可以获得值”xi pu jiao yu”。
如果要检查映射中是否包含某个值,可以使用contains方法。例如,在paste模式下,键入以下代码:
1. val xmu = if (university.contains("xipu")) university("xipu") else 0 2. println(xmu)
按下Ctrl+D,执行以上代码。输出结果如下:
xi pu jiao yu xmu: Any = xi pu jiao yu
上面我们定义的是不可变映射,是无法更新映射中的元素的,也无法增加新的元素。如果要更新映射的元素,就需要定义一个可变的映射。
在paste模式下,键入以下代码:
1. import scala.collection.mutable.Map 2. val university2 = Map("XMU" -> "xi pu jiao yu", "THU" -> "Tsinghua University","PKU"->"Peking University") 3. university2("XMU") = "西普教育" //更新已有元素的值 4. university2("ZZU") = "Zhengzhou University" //添加新元素
按下Ctrl+D,执行以上代码。输出结果如下:
import scala.collection.mutable.Map university2: scala.collection.mutable.Map[String,String] = Map(XMU -> xi pu jiao yu, THU -> Tsinghua University, ZZU -> Zhengzhou University, PKU -> Peking University)
如果要遍历映射,可以使用for循环语句。基本格式是:for ((k,v) <- 映射) 语句块
在paste模式下,键入以下代码:
1. val university = Map("XMU" -> "xi pu jiao yu", "THU" -> "Tsinghua University","PKU"->"Peking University") 2. for ((k,v) <- university) printf("代码: %s,名称: %s 3. ",k,v)
按下Ctrl+D,执行以上代码。输出结果如下:
代码: XMU,名称: xi pu jiao yu 代码: THU,名称: Tsinghua University 代码: PKU,名称: Peking University
或者,也可以只遍历映射中的k或者v。比如说,我们只想把所有键打印出来:
1. for (k<-university.keys) println(k)
输出结果如下:
XMU THU PKU
再比如说,我们只想把所有值打印出来:
1. for (v<-university.values) println(v)
输出结果如下:
xi pu jiao yu Tsinghua University Peking University
8.5 Scala异常处理
1、抛出异常。
Scala 抛出异常的方法和 Java一样,使用 throw 方法,例如,抛出一个新的参数异常:
1. throw new IllegalArgumentException
2、捕获异常。
异常捕捉的机制与其他语言中一样,如果有异常发生,catch字句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后。 如果抛出的异常不在catch字句中,该异常则无法处理,会被升级到调用者处。
捕捉异常的catch子句,语法与其他语言中不太一样。在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case字句。
在paste模式下,键入以下代码:
1. import java.io.FileReader 2. import java.io.FileNotFoundException 3. import java.io.IOException 4. 5. try { 6. val f = new FileReader("input.txt") 7. } catch { 8. case ex: FileNotFoundException =>{ 9. println("Missing file exception") 10. } 11. case ex: IOException => { 12. println("IO Exception") 13. } 14. }
按下Ctrl+D,执行以上代码。输出结果如下:
Missing file exception
catch字句里的内容跟match里的case是完全一样的。由于异常捕捉是按次序,如果最普遍的异常,Throwable,写在最前面,则在它后面的case都捕捉不到,因此需要将它写在最后面。
3、finally 语句。
finally 语句用于执行不管是正常处理还是有异常发生时都需要执行的步骤。
在paste模式下,键入以下代码:
1. import java.io.FileReader 2. import java.io.FileNotFoundException 3. import java.io.IOException 4. 5. try { 6. val f = new FileReader("input.txt") 7. } catch { 8. case ex: FileNotFoundException =>{ 9. println("Missing file exception") 10. } 11. case ex: IOException => { 12. println("IO Exception") 13. } 14. }finally { 15. println("Exiting finally...") 16. }
按下Ctrl+D,执行以上代码。输出结果如下:
Missing file exception Exiting finally…
9. 实验结果及分析:
实验结果运行准确,无误
10. 实验结论:
经过本节实验的学习,通过使用Shell的方式,学习了使用Scala基本语法,包含变量、表达式、流程控制,使用Scala定义函数定义和传递参数,包括位置参数、默认参数、名称参数,使用Scala常用集合数据结构,包括数组、列表、元组、Map,使用Scala进行异常处理,进一步巩固了我们的scala基础。
11. 总结及心得体会:
关于Scala中函数的定义和使用,总结如下:
scala使用def关键字定义函数。
def test() {
println(“Hello World!”);
}
因为是静态类型语言, 定义含参数和返回值的函数需要指定类型, 语法略有不同:
def add(x:Int, y:Int): Int = {
return x + y;
}
scala支持默认参数:
def add(x:Int = 0, y:Int = 0):Int = {
return x + y;
}
可以指定最后一个参数为可变参数, 从而接受数目不定的同类型实参:
def echo (args: String *) { for (arg <- args) println(arg) }
echo(“Hello”, “World”)
String *类型的参数args实际上是一个Array[String]实例, 但是不能将一个Array作为参数传给args.
若需传递Array作为实参,需要使用arr :_*传递实参:
val arr= Array(“Hello” , “World”)
echo(arr: _*)
命名参数允许以任意顺序传入参数:
def speed(dist:Double, time:Double):Double = {return dist / time}
speed(time=2.0, dist=12.2)
–end–