在方法返回类型上键入推断

时间:2010-02-05 17:48:30

标签: scala type-inference

为什么当方法中使用明确的return语句时,Scala无法推断方法的返回类型?

例如,为什么以下代码会编译?

object Main {
    def who = 5
    def main(args: Array[String]) = println(who)
}

但以下情况并非如此。

object Main {
    def who = return 5
    def main(args: Array[String]) = println(who)
}

4 个答案:

答案 0 :(得分:30)

方法的返回类型是块中定义它的最后一个语句的类型,或者是在没有块的情况下定义它的表达式的类型。

在方法中使用return时,会引入另一个方法可能返回的语句。这意味着Scala无法在找到它时确定return的类型。相反,它必须继续直到方法结束,然后组合所有出口点以推断它们的类型,然后返回到每个退出点并分配它们的类型。

这样做会增加编译器的复杂性并减慢它的速度,因为在使用return时不必指定返回类型。另一方面,在本系统中,推断返回类型免于Scala已经使用的有限类型推断。

所以,最后,在编译器复杂性与所获得的收益之间的平衡中,后者被认为不值得前者。

答案 1 :(得分:11)

这会增加编译器(和语言)的复杂性。在类似的东西上进行类型推断真的很时髦。与任何类型的推理相关,当你有一个表达式时,一切都会更好。分散的返回语句有效地创建了许多隐式分支,这些分支在统一时变得非常棘手。这不是特别,只是粘性。例如:

def foo(xs: List[Int]) = xs map { i => return i; i }

我问你,编译器在这里推断出什么?如果编译器使用显式返回语句进行推理,则需要Any。实际上,很多带有显式返回语句的方法最终都会返回Any,即使你没有偷偷摸摸非本地返回。就像我说的那样,粘性。

最重要的是,这不是一个应该鼓励的语言功能。显式返回提高代码清晰度,除非只有一个显式返回,并且在函数末尾。如果您将代码路径视为有向图,则很容易看出原因。正如我之前所说的,分散的返回会产生大量的隐式分支,这会在图形上产生奇怪的叶子,以及主体中的许多额外路径。这很时髦。如果您的分支都是显式的(模式匹配或if表达式),则更容易看到控制流,如果您不依赖于副作用return语句来生成代码,则代码将更加实用值。

因此,与Scala中的其他几个“气馁”功能(例如asInstanceOf而不是as)一样,该语言的设计者故意选择 less 愉快。这加上它引入类型推断的复杂性以及除了最人为的场景之外的所有结果的实际无用性。 scalac试图进行这种推理是没有任何意义的。

故事的道德:学会不分散你的回报!这是任何语言的好建议,而不仅仅是Scala。

答案 2 :(得分:1)

鉴于此(2.8.Beta1):

object Main {
  def who = return 5
  def main(args: Array[String]) = println(who)
}
<console>:5: error: method who has return statement; needs result type
         def who = return 5

......似乎不是无意中。

答案 3 :(得分:-2)

我不确定为什么。也许只是为了阻止使用return声明。 :)