无限循环似乎混淆了 Scala 的类型系统

Infinite loop seems to confuse Scala's type system

这是一个演示我的问题的人造玩具示例:

def sscce(): Int = {
  val rand = new Random()
  var count = 0
  while (true) {   // type mismatch; found: Unit, required: Int
    count += 1
    if (rand.nextInt() == 42) return count
  }
}

我怎样才能帮助编译器理解这个方法总是 return 一个 Int

我知道上面的玩具示例可以很容易地重构以完全摆脱无限循环,但我真的想要在我的实际代码中使用无限循环。相信我 ;)

总是 return 一个 Int:

def sscce(): Int = {
  val rand = new Random()
  var count = 0
  while (true) {
    count += 1
    if (rand.nextInt() == 42) return count
  }
  count // <-- this
}

看到这个 question。 While 循环不 return 一个值。即它们 return Unit 这是您函数中的最后一条语句。所以,定义说它 returns 一个 Int 但实际上它 returns Unit 因此类型错误。 @ionut 的回答通过 returning count 作为最后一条语句修复了类型错误,或者这是一种递归方法。

def sscce(): Int = {
  val rand = new Random()
  def ssccer(count: Int): Int = {
    if(rand.nextInt == 42) return count
    else ssccer(count + 1)
  }
  ssccer(0)
}

根据 SLSwhile 循环的执行方式类似于:

def whileLoop(cond: => Boolean)(body: => Unit): Unit  =
  if (cond) { body ; whileLoop(cond)(body) } else {}

即 returns Unit。因此编译器将 while 视为 sscce() 中的最后一条语句,因此假定您正在尝试 return Unit。我认为意识到 return count 最终 总是 return 和 Int.

是不够聪明的

简单的解决办法就是按照@Brian 或@IonutGStan 的建议,强制设置为return count,不管是否真的需要。

从代码质量的角度来看,放弃 while(true) 循环并用更具可读性的内容替换它会很好。作为一个很好的副作用,它也解决了你的问题:

def sscce(): Int = {
  val rand = new Random()
  var count = 1
  while (rand.nextInt() != 42) {
    count += 1
  }
  count
}

您还可以这样做:

def foo: Int = {
  ...
  while(true) {
    ... return ...
  }
  throw new IllegalStateException  // unreachable
}

这将进行类型检查,因为 throw 的类型是 Nothing,它是 Int.

的子类型