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

Posted

技术标签:

【中文标题】Scala 中的方法何时需要返回类型?【英文标题】:When is a return type required for methods in Scala? 【发布时间】:2011-03-08 19:39:29 【问题描述】:

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

我注意到有时我会收到错误消息“重载的方法(方法名)需要返回类型”,但并非一般规则必须始终为重载方法指定返回类型(我有一些我不明白的示例错误)。

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

【问题讨论】:

作为(我个人)风格的问题,除了最简单的方法(基本上,没有条件逻辑的单行方法)之外,我给出了所有明确的返回类型。请记住,如果您让编译器推断方法的结果类型,它可能比您想要的更具体。 (例如,HashMap 而不是 Map。) @Randall 是的,好点(关于返回类型太具体了)。 【参考方案1】:

Programming Scala 一书中的Chapter 2. Type Less, Do More 提到:

何时需要显式类型注释。

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

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

在方法中显式调用 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 可以推断它


Randall Schulzcmets:

就(我个人的)风格而言,我为除了最简单的方法(基本上是没有条件逻辑的单行)之外的所有方法都给出了明确的返回类型。

请记住,如果您让编译器推断方法的结果类型,它可能比您想要的更具体。 (例如,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 个元素的列表。 它创建一个包含一个元素(值 0)的 List[Int]。 因此,一个条件分支上的List[Int] 和另一个条件分支上的List[String] 概括为List[Any]。 在这种情况下,打字机并不过分 - 这是代码中的错误。 )

【讨论】:

"当推断的返回类型比您预期的更通用时,例如 Any。"这很奇怪。实际上,我认为这是 Typer 中的一个错误。我从来没有经历过这样的事情。你有例子吗? @soc: programming-scala.labs.oreilly.com/ch02.html 确实有一个示例,其中返回 List(0)(大小为 0 的 List)将返回并且 List[Any] 而不是 List[String],除非您指定返回类型。 List(0) 不会创建包含 0 个元素的列表。它创建一个包含一个元素的List[Int](值0)。因此,一个条件分支上的List[Int] 和另一个条件分支上的List[String] 概括为List[Any]。在这种情况下,打字机并不过分笼统——它是代码中的一个错误。这为指定返回类型添加了另一条规则:当您希望编译器验证函数中的代码是否返回您期望的类型时,请指定返回类型。 @Ken:很好的收获。我已将您的评论(和其他评论)包含在我的回答中。

以上是关于Scala 中的方法何时需要返回类型?的主要内容,如果未能解决你的问题,请参考以下文章

为啥重载的scala函数需要返回类型?

Scala - 如何返回这种 RDD 类型

Scala--第二天

Scala 中的 a += b 何时变为 a = a + b?

scala-从入门到精通

Scala 基础 :面向对象(下篇)