Scala编译器通常可以推断方法的返回类型,但在某些情况下需要指定返回类型。例如,递归方法需要指定返回类型。
我注意到有时候我收到错误消息“重载方法(methodname)需要返回类型”,但是一般规则是必须始终为重载方法指定返回类型(我有一些例子,我没有得到这个误差)。
何时需要指定返回类型,对于一般方法,特别是对于重载方法?
答案 0 :(得分:18)
Chapter 2. Type Less, Do More 一书的Programming Scala提及:
当需要显式类型注释时
实际上,您必须为以下情况提供明确的类型注释:
在以下情况下返回值的方法:
- 当您在方法中显式调用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()
}
重载方法有时可能需要显式返回类型。当一个这样的方法调用另一个时,我们必须向执行调用的方法添加一个返回类型,如本例所示。
// 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")) )
两个
joiner
方法将List
个字符串连接在一起 第一种方法也为分隔符字符串采用参数 第二种方法使用单个空格的“默认”分隔符调用第一个方法。如果您运行此脚本,则会收到以下错误。
... 9: error: overloaded method joiner needs result type
def joiner(strings: List[String]) = joiner(strings, "")
由于第二个
joiner
方法调用第一个,因此需要显式的String
返回类型。它应该是这样的:
def joiner(strings: List[String]): String = joiner(strings, " ")
基本上,指定返回类型可能是一个很好的做法,即使Scala可以推断它。
作为(我的个人)风格的问题,我为除了最简单的方法之外的所有方法提供了显式的返回类型(基本上,没有条件逻辑的单行)。
请记住,如果您让编译器推断出方法的结果类型,那么它可能比您想要的更具体。 (例如,HashMap而不是Map。)
由于您可能希望在返回类型中公开最小接口(例如参见此SO question),这种推断可能会妨碍。
关于最后一个场景(“当推断的返回类型比你想要的更通用”时),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
,我错误地解释了并且List [Any]因为返回一个空列表,但Ken称之为:
List(0)
不会创建包含0个元素的列表 它创建一个包含一个元素的List[Int]
(值为0) 因此,一个条件分支上的List[Int]
和另一个条件分支上的List[String]
一般化为List[Any]
。
在这种情况下, typer不是过于笼统 - 这是代码中的错误。
)