背景
- 表达式有值,语句执行动作。
- Scala中,几乎所有构造出来的语法结构都有值,不像Java中把表达式和语句(if语句)分为两类。
- 在这里if表示式有值。
- 代码块也有值,最后一个表达式就是值。
- 语句中,分号不是必需的。
- 函数式中不使用return。
条件表达式
- 在Scala中if/else表达式 有值,这个值就是在if或else之后的表达式的值。
1. `scala> var x = 10`
2. `x: Int = 10`
3.
4. `scala> val r = if (x > 0) 1 else -1`
5. `r: Int = 1`
6.
7. `scala> var x = 0`
8. `x: Int = 0`
9.
10. `scala> val r = if (x > 0) 1 else -1`
11. `r: Int = -1`
- 可能if没有输出值,但在Scala中,每个表达式都有某种值。
1. `scala> var x = 0`
2. `x: Int = 0`
3.
4. `scala> val r = if (x > 0) 1`
5. `r: AnyVal = ()`
块表达式和赋值
- 在Scala中{}块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
- 对于某个val的初始化需要分多步完成的情况很实用。
1. `val dis = {val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy)}`
循环
- while与Java中的循环一样。
1. `while(n > 0) {`
2. `r = r * n`
3. `n -= 1`
4. `}`
- Scala没有for(初始化; 检查变量是否满足; 更新变量)的结构。
1. `for(i <- 1 to n) {`
2. `r = r * i`
3. `}`
- 1 to n 表达式表示:返回数据1到n(包含)的区间。
- 1 until n 表达式表示:返回数据1到n(不包含)的区间。
增强for循环和for推导式
- 可以以 变量<-表达式的形式提供多个生成器,用分号将他们隔开
1. `scala> for(i <- 1 to 3; j <- 1 to 3) print ((10 * i + j) + " ")`
2. `11 12 13 21 22 23 31 32 33`
- 每个生成器都可以带一个守卫,以if开头的Boolean表达式 (if前并没有分号)
1. `scala> for(i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ")`
2. `12 13 21 23 31 32`
- for推导式:for循环的循环以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值
1. `scala> for(i <- 1 to 10) yield i % 3`
2. `res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)`
函数
- 函数定义:需要给出函数名、参数和函数体,格式如下
1. `def abs(x: Double) = if (x >= 0) x else -x`
- 必须给出所有参数的类型
- 递归函数必须指定返回值类型
1. `def fac(n: Int) : Int = if(n <= 0) 1 else n * fac(n - 1)`
- 不需要
return
语句 - 有
=
等号连接函数体 - 默认参数和带名参数
1. `scala> def decorate(str: String, left: String = "[", right: String = "]") = left + str + right`
2. `decorate: (str: String, left: String, right: String)String`
3.
4. `scala> decorate("Hello World")`
5. `res3: String = [Hello World]`
6.
7. `scala> decorate("Hello World", "<", ">")`
8. `res4: String = <Hello World>`
- 也可以在提供参数值时指定参数名,这样就可与函数定义参数列表的顺序不一致
1. `scala> decorate(left = "<<", str = "Hello Scala", right = ">>")`
2. `res5: String = <<Hello Scala>>`
- 可以混用未命名参数和带名参数,只要未命名的参数排在前面即可
1. `scala> decorate("Hello Spark", right = "]<<")`
2. `res6: String = [Hello Spark]<<`
3.
4. `相当于`
5.
6. `scala> decorate("Hello Spark", "[", "]<<")`
- 实现一个可以接受可变长参数列表的函数
1. `scala> def sum(args: Int*) = {`
2. `| var result = 0`
3. `| for (arg <- args) result += arg`
4. `| result`
5. `| }`
6. `sum: (args: Int*)Int`
7.
8. `scala> val s = sum(1, 3, 5, 7)`
9. `s: Int = 16`
- 可以使用
\_*
将一个整数区间转换成参数序列
1. `直接使用会抛出如下错误:`
2.
3. `scala> val ss = sum(1 to 5)`
4. `<console>:8: error: type mismatch;`
5. `found : scala.collection.immutable.Range.Inclusive`
6. `required: Int`
7. `val ss = sum(1 to 5)`
8.
9. `// 正确的使用方式`
10. `scala> val ss = sum(1 to 5: _*)`
11. `ss: Int = 15`
- 如果函数体包含在花括号当中,但没有前面的
=
号,返回类型是Unit,这样的函数被称做过程。过程不返回值,调用它仅仅是为了它的副作用。 - 当val被声明为lazy时,它的始始化将被推迟,直到首次对它取值。
1. `lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString`
2.
3. `可以故意把文件名写错,试一下在初始化语句被执行的时候会不会报错(只有访问words时才提示文件未找到)`
敬请期待下一篇~