简体   繁体   English

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

[英]Infinite loop seems to confuse Scala's type system

Here is an artificial toy example that demonstrates my problem: 这是一个人工玩具示例,演示了我的问题:

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

How can I help the compiler understand that this method will always return an Int ? 我怎样才能帮助编译器理解这个方法总会返回一个Int

I know the above toy example could easily be refactored to get rid of the infinite loop altogether, but I really want to have the infinite loop in my actual code. 我知道上面的玩具示例很容易被重构以完全摆脱无限循环,但我真的希望在我的实际代码中有无限循环。 Trust me on this ;) 相信我;)

Always return an Int : 总是返回Int

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

You can also do: 你也可以这样做:

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

this will typecheck because the type of the throw is Nothing , which is a subtype of Int . 这将是类型检查,因为throw的类型是Nothing ,这是Int的子类型。

See this question . 看到这个问题 While loops don't return a value. while循环不返回值。 ie they return Unit which is the last statement in your function. 即它们返回Unit ,它是函数中的最后一个语句。 So, the definition says it returns an Int but it actually returns Unit thus the type error. 所以,定义说它返回一个Int但它实际上返回Unit因此返回了类型错误。 @ionut's answer fixes the type error by returning count as the last statement or here is a recursive approach. @ ionut的答案通过将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)
}

Per the SLS , a while loop is executed similarly to: 根据SLSwhile循环的执行方式与:

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

ie., it returns Unit . 即,它返回Unit So the compiler sees the while as the last statement in sscce() , and therefore assumes that you're trying to return Unit . 因此编译器将while视为sscce()的最后一个语句,因此假设您正在尝试返回Unit I don't think it's smart enough to realize that return count will eventually always return an Int . 我不认为它很聪明地意识到return count 最终将总是返回Int

The simple solution is to follow the suggestion of @Brian or @IonutGStan, and force it to return count , whether it truly needs it or not. 简单的解决方案是遵循@Brian或@IonutGStan的建议,并强制它返回count ,无论它是否真正需要它。

From a code quality standpoint, it would be good to ditch the while(true) loop and replace it with something more readable. 从代码质量的角度来看,放弃while(true)循环并将其替换为更具可读性的东西将是一件好事。 As a nice side effect, it also solves your problem: 作为一个很好的副作用,它也解决了你的问题:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM