Scala中的简单类型推断

时间:2009-10-07 07:05:44

标签: scala type-inference

我一直在研究Scala中的类型推断,并且有一些事情我想更好地理解为什么必须在少数情况下显式声明表达式/方法返回类型。

明确的return声明

示例(如果省略return关键字,则有效):

def upCase(s: String) = {
  if (s.length == 0)
    return s    // COMPILE ERROR - forces return type of upCase to be declared.
  else
    s.toUpperCase()
}

为什么我不能在不声明返回类型的情况下将显式类型参数用作返回值?这不仅适用于直接参数引用,也适用于任何“类型可推断”表达式。

方法重载

示例(添加第二个joiner方法时无法编译):

def joiner(ss: List[String], sep: String) = ss.mkString(sep)

def joiner(ss: List[String]) = joiner(strings, " ")   // COMPILE ERROR WHEN ADDED

5 个答案:

答案 0 :(得分:3)

最明显的答案是:因为它在规范中说明了scala参考的第6.20部分。但为什么这样设计确实是非常有趣的问题。我怀疑它与编译器无法预测表达式将是最后一个的事实有关,因为返回改变了执行流程。

修改

考虑返回在代码后是否需要显式返回类型:

def bar() = {   
  if(guard())  
    return "SS"  
  else if(gurard1())  
    return true   
  2  
}

那种返回类型应该在这种情况下?嗯,有最常见的超类型的选项,但我认为它会让我们在许多情况下返回任何。那么这只是我的想法,这可能是完全错误的=)

答案 1 :(得分:2)

函数或方法的类型是从其最后一个语句的类型推断出来的。通常,这是一个表达。

现在,“return”打破了控制流程。可以说,这是一个“直接中断”。因此,不能再使用用于推断表达式类型的常规规则。当然,它仍然可以完成,但我猜测编译器复杂性的成本被认为是高回报。

以下是流程如何被破坏的示例:

def toNumber(s: String) = {
  if (s == null)
    return ""

  if (s matches """\d+""")
    s.toInt
  else
    0
}

通常,第二个if语句的类型将用于推断整个函数的类型。但是第一个return上的if引入了该函数的第二个返回点,因此该规则不起作用。

答案 2 :(得分:1)

类型推断在可能的情况下推断出方法的返回类型,在任何情况下该方法都不是递归的。

如果您将其更改为:

,您的示例将有效
def upCase(s: String) = {
 if (s.length == 0)
   s    // note: no return
 else
   s.toUpperCase()
}

我不知道为什么返回会改变这一点。

答案 3 :(得分:0)

免责声明 - 此答案针对最初发布的问题

Scala的类型推断已经推断出方法/表达式的返回类型:

scala> def foo(s : String) = s + " Hello"
foo: (String)java.lang.String

scala> var t = foo("World")
t: java.lang.String = World Hello

scala> def bar( s : String) = s.toInt
bar: (String)Int

scala> var i = bar("3")
i: Int = 3

和:

scala> var j = if (System.getProperty("user.name") == "oxbow") 4 else "5".toInt
j: Int = 5

编辑 - 我没有意识到包含return关键字意味着必须显式声明表达式的返回类型:我几乎停止使用{ {1}}我自己 - 但这是一个有趣的问题。对于return示例,必须声明返回类型,因为重载。同样,我不知道为什么和有兴趣了解的详细信息。我怀疑一个更好的问题主题会引起James Iry,Dan Spiewak或Daniel Sobral等人的回答。

答案 4 :(得分:0)

我怀疑方法重载(缺少)推断与递归调用的类似问题有关,因为如果重载的方法不相互调用,它可以完美地工作:

  def joiner1(ss: List[String], sep: String) = ss.mkString(sep)
  def joiner(ss: List[String], sep: String) = ss.mkString(sep)
  def joiner(ss: List[String]) = joiner1(ss, " ")  

有两个重载的joiner方法,但是代码编译正确推断出类型。