2

一些算法执行条件为 true 的 while 循环,并且(肯定)会在某个点以 while 循环体内的 return 语句结束。例如:

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 // !
}

但这看起来很难看。有更好的解决方法吗?甚至是解决此类问题的更好方法?

4

4 回答 4

14

你可以抛出一个异常:

def foo: Int = {
  var i = 0
  while(true) {
    i += 1
    if(i == 10)
      return 0
  }
  throw new IllegalStateException("This should never happen")
}

编译器将停止抱怨类型不匹配,并且由于 while 循环总是返回一些东西,所以永远不会抛出异常。如果是这样,您将很快发现您做错了什么:)。

还有其他方法可以编写这个循环,它们更符合规范和 Scala 风格,但鉴于您提供的代码,这将以一种清晰简单的方式完成工作。

于 2012-08-22T09:41:14.067 回答
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它有一个参数。

于 2012-08-22T09:50:46.623 回答
3

更惯用的方法是使用递归。像这样的东西:

  def foo: Int = { 
    import scala.annotation.tailrec
    @tailrec def whileUnderTen(i: Int):Int = if ( i < 10) whileUnderTen(i+1) else 0
    whileUnderTen(0)
  }
于 2012-08-22T09:56:07.540 回答
1

对于这些场合,我在我的个人标准库中定义了一个“永远”的构造。

forever{
}

在所有方面都等同于

while(true){
}

except that forever has type Nothing while the equivalent while construct has type Unit. Just one of those small extension capabilities that makes Scala such a joy.

于 2012-08-22T23:37:22.027 回答