- Scala编程(第5版)
- (德)马丁·奥德斯基等
- 1199字
- 2022-05-06 15:51:49
7.2 while循环
Scala的while循环与其他语言中的没有多大差别。它包含了一个条件检查和一个循环体,只要条件检查为真,就会一遍接一遍地执行循环体。参考示例7.2。
示例7.2 用while循环计算最大公约数
我们把while这样的语法结构称为“循环”而不是表达式,是因为它并不会返回一个有意义的值,其返回值的类型是Unit。实际上存在这样一个(也是唯一的一个)类型为Unit的值,这个值叫作单元值(unit value),被写作()。存在这样一个()值,可以说是Scala的Unit与Java的void的不同。可以尝试在编译器中输入:
由于表达式println("hi") 的类型为Unit,因此greet被定义为一个结果类型为Unit的过程。这样一来,greet返回单元值()。这一点在接下来的一行中得到了印证:对greet的结果和单元值()进行相等性判断,得到true。
Scala 3不再提供do-while循环,这是一个在循环体之后执行条件检查而不是在循环体之前执行条件检查的控制结构。取而代之的是,可以将循环体对应的语句直接写在while之后,然后以do()收尾。示例7.3展示了使用这种编写方式来打印从标准输入中读取的文本行直到用户输入空白行为止的Scala脚本。
示例7.3 在不使用do-while循环的情况下至少执行一遍循环体
另一个相关的返回单元值的语法结构是对var的赋值。例如,当你尝试在Scala中像Java(或C/C++)的while循环惯用法那样使用while循环时,会遇到问题:
在编译这段代码时,Scala编译器会给出一个警告:用!=对类型为Unit的值和String做比较将永远返回true。在Java中,赋值语句的结果是被赋予的值(在本例中就是从标准输入中读取的一行文本),而在Scala中赋值语句的结果永远是单元值()。因此,赋值语句“line = readLine()”将永远返回(),而不是""。这样一来,while循环的条件检查结果永远都不会为false,从而导致循环无法终止。
由于while循环没有返回值,因此纯函数式编程语言通常都不支持while循环。这些语言有表达式,但没有循环。尽管如此,Scala还是包括了while循环,因为有时候指令式的解决方案更易读,尤其是对那些以指令式编程风格为主的程序员而言。举例来说,如果你想要编写一段重复某个处理逻辑直到某个条件发生变化为止的算法的代码时,则while循环能够直接表达出来,而函数式的替代方案(可能用到了递归)对某些读者而言就没有那么直观了。
例如,示例7.4给出了一个计算两个数的最大公约数的另一种实现方式。[1]给x和y同样的两个值,示例7.4的gcd函数将返回与示例7.2中的gcdLoop函数相同的结果。这两种方案的区别在于gcdLoop是指令式编程风格的,用到了var和while循环,而gcd是更加函数式编程风格的,用到了递归(gcd调用了自己),并且不需要var。
示例7.4 用递归计算最大公约数
一般来说,我们建议你像挑战var那样挑战代码中的while循环[2]。事实上,while循环和var通常都是一起出现的。由于while循环没有返回值,因此要想对程序产生任何效果,while循环通常要么更新一个var,要么执行I/O。先前的gcdLoop示例已经很好地展示了这一点。在这个while循环执行过程中,更新了var变量a和b。因此,我们建议你对代码中的while循环保持警惕。如果对于某个特定的while循环,我们找不到合理的理由来使用它,那么应该尝试采用其他方案来完成同样的工作。