何时是Scala中方法所需的返回类型?

Jes*_*per 12 methods scala overloading scala-2.8

Scala编译器通常可以推断方法的返回类型,但在某些情况下需要指定返回类型.例如,递归方法需要指定返回类型.

我注意到有时我得到错误消息"重载方法(methodname)需要返回类型",但是一般规则是必须始终为重载方法指定返回类型(我有一些例子,我没有得到这个错误).

何时需要指定返回类型,对于一般的方法,特别是对于重载方法?

Von*_*onC 19

第2章种类比较少,做的更多的的编程斯卡拉书中提到:

何时需要显式类型注释.

实际上,您必须为以下情况提供显式类型注释:

方法在以下情况下返回值:

  • 当您在方法中显式调用return时(即使在结尾处).
  • 当一个方法是递归的.
  • 当方法重载并且其中一个方法调用另一个方法时.调用方法需要返回类型注释.
  • 当推断的返回类型比您预期的更通用时,例如,Any.

例:

// code-examples/TypeLessDoMore/method-nested-return-script.scala
// ERROR: Won't compile until you put a String return type on upCase.

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

重载方法有时可能需要显式返回类型.当一个这样的方法调用另一个时,我们必须向执行调用的方法添加一个返回类型,如本例所示.

// code-examples/TypeLessDoMore/method-overloaded-return-script.scala
// Version 1 of "StringUtil" (with a compilation error).
// ERROR: Won't compile: needs a String return type on the second "joiner".

object StringUtil {
  def joiner(strings: List[String], separator: String): String =
    strings.mkString(separator)

  def joiner(strings: List[String]) = joiner(strings, " ")   // ERROR
}
import StringUtil._  // Import the joiner methods.

println( joiner(List("Programming", "Scala")) )
Run Code Online (Sandbox Code Playgroud)

这两种joiner方法List将一串字符串连接在一起.
第一种方法还为分隔符字符串采用参数.
第二种方法使用单个空格的"默认"分隔符调用第一个方法.

如果您运行此脚本,则会收到以下错误.

... 9: error: overloaded method joiner needs result type
def joiner(strings: List[String]) = joiner(strings, "")
Run Code Online (Sandbox Code Playgroud)

由于第二个joiner方法调用第一个方法,因此它需要显式String返回类型.它应该如下所示:

def joiner(strings: List[String]): String = joiner(strings, " ")
Run Code Online (Sandbox Code Playgroud)

基本上,指定返回类型可能是一个很好的做法,即使Scala可以推断它.


Randall Schulz评论道:

作为(我的个人)风格的问题,我为除了最简单的方法之外的所有方法提供了显式的返回类型(基本上,没有条件逻辑的单行).

请记住,如果让编译器推断出方法的结果类型,它可能比您想要的更具体.(例如,HashMap而不是Map.)

而且由于您可能希望在返回类型中公开最小接口(例如参见此SO问题),因此这种推断可能会受到阻碍.


关于最后一个场景("当推断的返回类型比你预期的更为普遍"时),Ken Bloom补充道:

如果希望编译器验证函数中的代码是否返回预期的类型,请指定返回类型

(触发"比预期更通用的返回类型的错误代码是:

// code-examples/TypeLessDoMore/method-broad-inference-return-script.scala
// ERROR: Won't compile. Method actually returns List[Any], which is too "broad".

def makeList(strings: String*) = {
  if (strings.length == 0)
    List(0)  // #1
  else
    strings.toList
}

val list: List[String] = makeList()  // ERROR
Run Code Online (Sandbox Code Playgroud)

,我错误地解释和List [Any]因为返回一个空列表,但Ken称之为:

List(0)不会创建包含0个元素的列表.
它创建一个List[Int]包含一个元素(值0).
因此List[Int],一个条件分支和List[String]另一个条件分支一般化List[Any].
在这种情况下,typer不是过于笼统 - 这是代码中的错误.
)

  • `List(0)`不会创建一个包含0个元素的列表.它创建一个包含一个元素(值为"0")的`List [Int]`.因此,一个条件分支上的`List [Int]`和另一个条件分支上的`List [String]`一般化为`List [Any]`.在这种情况下,typer不是过于笼统 - 这是代码中的错误.这为指定返回类型添加了另一个规则:**当您希望编译器验证函数中的代码返回您期望的类型时,指定返回类型.** (2认同)