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

发布于 2024-09-07 22:11:39 字数 179 浏览 4 评论 0 原文

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

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

到底什么时候需要为一般方法和特别是重载方法指定返回类型?

The Scala compiler can often infer return types for methods, but there are some circumstances where it's required to specify the return type. Recursive methods, for example, require a return type to be specified.

I notice that sometimes I get the error message "overloaded method (methodname) requires return type", but it's not a general rule that return types must always be specified for overloaded methods (I have examples where I don't get this error).

When exactly is it required to specify a return type, for methods in general and specifically for overloaded methods?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柒夜笙歌凉 2024-09-14 22:11:39

第 2 章:少输入,多做 href="http://programming-scala.labs.oreilly.com/index.html" rel="nofollow noreferrer">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问题),这种推断可能会妨碍。


关于最后一个场景(“当推断的返回类型比您预期的更通用时”),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]。< br>
在本例中,打字机并不是过于通用——它是代码中的一个错误

The Chapter 2. Type Less, Do More of the Programming Scala book mentions:

When Explicit Type Annotations Are Required.

In practical terms, you have to provide explicit type annotations for the following situations:

Method return values in the following cases:

  • When you explicitly call return in a method (even at the end).
  • When a method is recursive.
  • When a method is overloaded and one of the methods calls another. The calling method needs a return type annotation.
  • When the inferred return type would be more general than you intended, e.g., Any.

Example:

// 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()
}

Overloaded methods can sometimes require an explicit return type. When one such method calls another, we have to add a return type to the one doing the calling, as in this example.

// 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")) )

The two joiner methods concatenate a List of strings together.
The first method also takes an argument for the separator string.
The second method calls the first with a “default” separator of a single space.

If you run this script, you get the following error.

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

Since the second joiner method calls the first, it requires an explicit String return type. It should look like this:

def joiner(strings: List[String]): String = joiner(strings, " ")

Basically, specifying the return type can be a good practice even though Scala can infer it.


Randall Schulz comments:

As a matter of (my personal) style, I give explicit return types for all but the most simple methods (basically, one-liners with no conditional logic).

Keep in mind that if you let the compiler infer a method's result type, it may well be more specific than you want. (E.g., HashMap instead of Map.)

And since you may want to expose the minimal interface in your return type (see for instance this SO question), this kind of inference might get in the way.


And about the last scenario ("When the inferred return type would be more general than you intended"), Ken Bloom adds:

specify the return type when you want the compiler to verify that code in the function returns the type you expected

(The faulty code which triggers a "more general than expected return type was:

// 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

, which I incorrectly interpreted and List[Any] because returning an empty List, but Ken called it out:

List(0) doesn't create a list with 0 elements.
It creates a List[Int] containing one element (the value 0).
Thus a List[Int] on one conditional branch and a List[String] on the other conditional branch generalize to List[Any].
In this case, the typer isn't being overly-general -- it's a bug in the code.
)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文