【问题标题】:Infinite loop seems to confuse Scala's type system无限循环似乎混淆了 Scala 的类型系统
【发布时间】:2015-03-07 00:21:08
【问题描述】:

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

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

如何帮助编译器了解此方法将始终返回 Int

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

【问题讨论】:

  • 从技术上讲,您的代码不会返回 Int。它返回一个 Int if 该函数完全返回。我怀疑这种区别是问题所在。你想解决什么问题?你说你真的想要一个无限循环,但也许你现实世界的问题可以有另一种解决方案。
  • 我真的很喜欢无限循环,但它们需要很长时间才能完成。
  • 你不能证明它会一直被执行,因为它不会一直被执行。它通常会被执行,但 scala 不提供 Usually[Int] 类型。如果没有更好的方法来代替使用无限循环,我会感到震惊。

标签: scala infinite-loop type-inference return-type


【解决方案1】:

始终返回Int

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

【讨论】:

    【解决方案2】:

    你也可以这样做:

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

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

    【讨论】:

      【解决方案3】:

      看到这个question。 While 循环不返回值。即它们返回Unit,这是您函数中的最后一条语句。所以,定义说它返回一个Int,但它实际上返回Unit,因此是类型错误。 @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)
      }
      

      【讨论】:

        【解决方案4】:

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

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

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

        简单的解决方案是遵循@Brian 或@IonutGStan 的建议,并强制它返回count,不管它是否真的需要它。

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-22
            • 1970-01-01
            • 2015-11-09
            • 1970-01-01
            相关资源
            最近更新 更多