条件表达式
Scala的if/else语法结构和Java或C++一样。不过,在Scala中if/else表达式有值,这个值就是跟在if或else之后的表达式的值。例如:
if (x > 0) 1 else -1
上述表达式的值是1或−1,具体是哪一个取决于x的值。你可以将if/else表达式的值赋值给变量:
val s = if (x > 0) 1 else -1
这与如下语句的效果一样:
if (x > 0) s = 1 else s = -1
不过,第一种写法更好,因为它可以用来初始化一个val。而在第二种写法当中,s必须是var。
(之前已经提过,Scala中的分号绝大多数情况下不是必需的。)
Java和C++有一个?:操作符用于同样目的。如下表达式
x > 0 ? 1 : -1 // Java或C++
等同于Scala表达式 if (x > 0) 1 else −1。不过,你不能在?:表达式中插入语句。Scala的if/else将在Java和C++中分开的两个语法结构if/else和?:结合在了一起。
在Scala中,每个表达式都有一个类型。举例来说,表达式 if (x > 0) 1 else −1的类型是Int,因为两个分支的类型都是Int。混合类型表达式,比如:
if (x > 0) "positive" else -1
上述表达式的类型是两个分支类型的公共超类型。在本例中,其中一个分支是java.lang.String,而另一个分支是Int。它们的公共超类型叫做Any。(详细内容参见8.11节。)
如果else部分缺失了,比如:
if (x > 0) 1
那么有可能if语句没有输出值。但是在Scala中,每个表达式都应该有某种值。这个问题的解决方案是引入一个Unit类,写做()。不带else的这个if语句等同于
if (x > 0) 1 else ()
你可以把()当做是表示“无有用值”的占位符,将Unit当做Java或C++中的void。(从技术上讲,void没有值但是Unit有一个表示“无值”的值。如果你一定要深究的话,这就好比空的钱包和里面有一张写着“没钱”的无面值钞票的钱包之间的区别。)
说明:Scala没有switch语句,不过它有一个强大得多的模式匹配机制,我们将在第14章中看到。在现阶段,用一系列的if语句就好。
注意:REPL比起编译器来更加“近视”——它在同一时间只能看到一行代码。
举例来说,当你键入如下代码时:
if (x > 0) 1
else if (x == 0) 0 else -1
REPL会执行 if (x > 0) 1,然后显示结果。之后它看到接下来的else关键字就会不知所措。
如果你想在else前换行的话,用花括号:
if (x > 0) { 1
} else if (x == 0) 0 else -1
只有在REPL中才会有这个顾虑。在被编译的程序中,解析器会找到下一行的else。
提示:如果你想在REPL中粘贴成块的代码,而又不想担心REPL的近视问题,可以使用粘贴模式。键入:
:paste
把代码块粘贴进去,然后按下Ctrl+D。这样REPL就会把代码块当做一个整体来分析。
语句终止
在Java和C++中,每个语句都以分号结束。而在Scala中——与JavaScript和其他脚本语言类似——行尾的位置不需要分号。同样,在}、else以及类似的位置也不必写分号,只要能够从上下文明确地判断出这里是语句的终止即可。
不过,如果你想在单行中写下多个语句,就需要将它们以分号隔开。例如:
if (n > 0) { r = r * n; n -= 1 }
我们需要用分号将 r = r * n 和 n -= 1 隔开。由于有},在第二个语句之后并不需要写分号。
如果你在写较长的语句,需要分两行来写的话,就要确保第一行以一个不能用做语句结尾的符号结尾。通常来说一个比较好的选择是操作符:
s = s0 + (v - v0) * t + // +告诉解析器这里不是语句的末尾
0.5 * (a - a0) * t * t
在实际编码时,长表达式通常涉及函数或方法调用,如此一来你并不需要过分担心——在左括号(之后,编译器直到看到匹配的)才会去推断某处是否为语句结尾。
正因如此,Scala程序员们更倾向于使用Kernighan & Ritchie风格的花括号:
if (n > 0) {
r = r * n
n -= 1
}
以{结束的行很清楚地表示了后面还有更多内容。
许多来自Java或C++的程序员一开始并不适应省去分号的做法。如果你倾向于使用分号,用就是了——它们没啥坏处。
块表达式和赋值
在Java或C++中,块语句是一个包含于{ }中的语句序列。每当你需要在逻辑分支或循环中放置多个动作时,你都可以使用块语句。
在Scala中,{ }块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
这个特性对于那种对某个val的初始化需要分多步完成的情况很有用。例如,
val distance = { val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy) }
{ }块的值取其最后一个表达式,在此处以粗体标出。变量dx和dy仅作为计算所需要的中间值,很干净地对程序其他部分而言不可见了。
在Scala中,赋值动作本身是没有值的——或者,更严格地说,它们的值是Unit类型的。你应该还记得,Unit类型等同于Java和C++中的void,而这个类型只有一个值,写做()。
一个以赋值语句结束的块,比如
{ r = r * n; n -= 1}
的值是Unit类型的。这没有问题,只是当我们定义函数时需要意识到这一点。
由于赋值语句的值是Unit类型的,别把它们串接在一起。
x = y = 1 // 别这样做
y = 1的值是(),你几乎不太可能想把一个Unit类型的值赋值给x。(与此相对应,在Java和C++中,赋值语句的值是被赋的那个值。在这些语言中,将赋值语句串接在一起是有意义的。)
输入和输出
如果要打印一个值,我们用print或println函数。后者在打印完内容后会追加一个换行符。举例来说,
print("Answer: ")
println(42)
与下面的代码输出的内容相同:
println("Answer: " + 42)
另外,还有一个带有C风格格式化字符串的printf函数:
printf("Hello, %s! You are %d years old.\n", "Fred", 42)
你可以用readLine函数从控制台读取一行输入。如果要读取数字、Boolean或者是字符,可以用readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean或者readChar。与其他方法不同,readLine带一个参数作为提示字符串:
val name = readLine("Your name: ")
print("Your age: ")
val age = readInt()
printf("Hello, %s! Next year, your will be %d.\n", name, age + 1)
本文节选自《快学Scala》
电子工业出版社出版
(美)霍斯曼(Horstmann,C.S.)著
高宇翔译
相关推荐
4. **模式匹配**:Scala的模式匹配功能允许开发者通过单一表达式来处理多种情况,简化了条件判断和数据解析。 5. **集合库**:Scala的集合库是其一大亮点,提供了丰富的数据结构,如List、Set、Map,以及高效的操作...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性,被广泛应用于大...在阅读《快学Scala》完整版书籍.pdf时,应着重理解每个概念的含义、用法以及在实际编程中的应用,以便于在实践中灵活运用。
在大数据课程中,Scala编程基础是一个重要的组成部分,特别是在学习如何高效处理大规模数据时。本课程内容涵盖多个关键概念,如模式匹配、样例类、隐式函数和异常处理及泛型,这些都是Scala语言强大特性的体现。 ...
4. **模式匹配**:Scala中的模式匹配允许开发者在单一表达式中执行解构和条件判断,提高了代码的可读性和简洁性。 5. ** Actors模型**:Scala内置对Akka Actors的支持,这是一种用于构建并发和分布式系统的模型,...
4. **表达式和模式匹配**:Scala中的几乎一切都是表达式,这意味着每个语句都能产生一个值。模式匹配允许程序员优雅地处理复杂的解构和条件判断。 5. **类型推断**:Scala的编译器能自动推断变量和函数的类型,减少...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式...通过深入研究这个"scala-2.12.0.tgz"压缩包,开发者不仅可以掌握Scala编程语言,还可以了解如何在实际项目中应用这些知识,提升技能和解决问题的能力。
在Scala中使用正则表达式时,编译正则表达式通常比直接使用字符串字面量更高效。编译后的正则表达式可以被复用,这在处理多个文本或重复匹配时可以显著提高性能。此外,模式匹配与正则表达式结合使用时,能够实现...
在"第4讲-Scala编程详解:条件控制与循环"中,我们将深入探讨几个关键的编程概念,这些概念对于任何程序员来说都是至关重要的。下面是对每个主题的详细说明: 1. **if表达式**: Scala的`if`表达式不仅仅是一个...
6. 表达式:是Scala编程中最为核心的组成部分之一,涉及表达式的类型化、字面值、指示器、函数应用、方法值、类型应用、元组、实例创建表达式、代码块、前后缀及后缀运算、赋值、条件表达式、循环表达式、匿名函数、...
在Scala中,可以使用递归函数实现算法,但为了优化,推荐使用尾递归,即函数的最后一步是调用自身,且调用的参数不依赖于当前的计算结果。 匿名函数是不需要名称的函数,常用于需要函数对象的地方,如`List.map`或`...
3. **条件表达式**:类似于其他语言的if-else结构,Scala中的条件表达式不仅用于控制流程,还可以直接作为返回值。 4. **牛顿法求平方根**:书中用牛顿法求平方根的例子来展示如何编写递归函数。递归是Scala中重要...
3. 条件表达式和循环表达式:Scala中的条件表达式使用if进行,循环表达式支持for循环,但Scala没有break和continue关键字。在需要提前退出循环时,通常使用返回值和函数式编程技巧来实现。 4. 类和对象:Scala中类...
而在Java 8中,可以使用流(Stream)和Lambda表达式简化这一过程: ```java Map, Integer> authorsToAge = Stream.of(new Object[][] { { "Raoul", 23 }, { "Mario", 40 }, { "Alan", 53 } }).collect(Collectors....
Scala中的函数也可以是匿名的,这意味着可以在任何地方定义和使用一个简单的函数,而无需为它命名。 在Scala中,一个函数式编程的核心概念是"头等函数"(first-class functions),即函数可以作为参数传递给其他...
Scala中的条件表达式不仅可以用于简单的条件分支,还支持混合类型的表达式。例如: ```scala package cn.itcast.scala object ConditionDemo { def main(args: Array[String]): Unit = { val x = 1 val y = if ...
4. **表达式语法**:Scala 的语法鼓励使用表达式而不是语句,这使得代码更具有可读性,比如使用 if-then-else 表达式和 for 循环。 5. **Actor 模型**:Scala 与 Akka 框架集成良好,Akka 提供了基于 Actor 模型的...
7. **表达式导向编程**:Scala鼓励使用表达式而非语句,使得代码更加简洁且易于理解。 在IntelliJ IDEA中,开发者可以利用其强大的调试器来跟踪和定位代码中的问题,通过单元测试工具进行测试驱动开发,以及与其他...