有些算法执行一个带有条件为true的while循环,并且(肯定)会在某个时刻以while循环体内的return语句结束。 E.g:
def foo: Int = {
while(true) {
// At some time, the while loop will do a return statement inside its body
if( ... )
return 0
}
}
简单的例子(没有语义意义):
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
}
Scala编译器抱怨类型不匹配,因为while循环的类型为Unit而编译器不知道,while循环将在某个时刻返回一个值。我们可以通过以下方法解决此问题:
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
0 // !
}
但这看起来很难看。有更好的解决方法吗?或者甚至是解决这类问题的更好方法?
答案 0 :(得分:13)
你可以抛出异常:
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
throw new IllegalStateException("This should never happen")
}
编译器将停止抱怨类型不匹配,并且由于while循环总是返回某些内容,因此永远不会抛出异常。如果是的话,你会很快发现你做错了什么:)。
还有其他方法可以编写这个循环,它更像是idomatic和Scala-esque,但是考虑到你提供的代码,这将以清晰简单的方式完成工作。
答案 1 :(得分:8)
也许你应该只使用尾递归。它应该最终编译成非常相似的字节码:
import scala.annotation.tailrec
def foo: Int = {
@tailrec def bar(i: Int): Int = {
val j = i + 1
if (j == 10) return 0
else bar(j)
}
bar(0)
}
您甚至可能希望使用默认参数值支持:
@tailrec def foo(i: Int = 0): Int = {
val j = i + 1
if (j == 10) return 0
else foo(j)
}
请注意,这种方式要求您将函数调用为foo()
而不是foo
,因为它有一个参数。
答案 2 :(得分:3)
更惯用的方法是使用递归。像这样:
def foo: Int = {
import scala.annotation.tailrec
@tailrec def whileUnderTen(i: Int):Int = if ( i < 10) whileUnderTen(i+1) else 0
whileUnderTen(0)
}
答案 3 :(得分:1)
对于这些场合,我在我的个人标准库中定义了“永久”构造。
forever{
}
在各方面都等同于
while(true){
}
除了forever
的类型为Nothing
,而等效的while
结构的类型为Unit
。只是其中一个小扩展功能,使Scala如此高兴。