何时应该在Scala方法def中使用显式定义的返回类型?

4

Scala风格指南建议始终明确定义返回类型,除非使用 Unit

Methods should be declared according to the following pattern:

def foo(bar: Baz): Bin = expr

The only exceptions to this rule are methods which return Unit. Such methods should use Scala's syntactic sugar to avoid accidentally confusing return types:

def foo(bar: Baz) { // return type is Unit
  expr
}

2
Martin Odersky建议避免过程语法。参见Scala with Style第45章。也请参考this answer的评论讨论。 - senia
1
@senia 好的,如果过程语法不好,那么更好的方法是明确声明 Unit 作为返回类型还是省略它(编译器会自动推断类型)? - WelcomeTo
就像任何其他类型一样。在某些指南中,建议在公共方法中明确指定类型。我想这是一个主要基于个人观点的问题。 - senia
顺便提一下,如果你编写递归函数,返回类型是必需的。 - Björn Jacobs
1
通常情况下,您应该在公共API中定义返回类型,以隐藏实现特定的类型。 - Sergey Passichenko
1个回答

2
作为评论员们所指出的,Martin Odersky在链接的主题演讲中讨论了这个问题。当然,“何时...”只是一个风格问题,因此只能提供意见。
两件事:(1) 类型是否需要明确,(2) 是否需要注释过程语法。
(1) 显然,对于纯API(没有实现的情况下),必须指定返回类型。我会将其扩展到任何同时也是API的方法实现。也就是说,如果您的方法不是实现特征,则应该注释该方法。私有和本地方法可以推断返回类型,除非您在第一眼难以确定类型,或者您被迫这样做(例如,在递归方法调用中)。还有人说,当你给出明确的返回类型时,编译速度更快。
(2) 如果您具有易于返回的简短方法,则认为推断是可以接受的。例如:
trait Foo {
  def sqrt(d: Double) = math.sqrt(d)

  def toString = "Foo"

  def bar = new Bar(123)
}

(但是有人可能会争论,math.sqrt 返回一个 Double 并不显而易见)。

虽然更冗长,但这样做可以使代码更易读,并避免(a)泄露关于实现或子类型的信息,其中超类型已经足够:

trait Before {
  def bar = new BarImpl

  def seq = Vector(1, 2, 3)
}

trait After {
  def bar: Bar = new BarImpl

  def seq: IndexedSeq[Int] = Vector(1, 2, 3)
}

而且 (b) 你要避免意外地从结构类型返回到错误的集合类型等,以避免不必要的麻烦。


(2) 直到最近,我更喜欢过程语法,但在重新讨论和许多人表达他们对它的不满后,我尝试使用显式的 : Unit = 注释,现在我更喜欢它了。我认为过程语法清楚地表明了方法具有副作用,但实际上 : Unit = 也很清楚地表明了这一点。此外,它通常可以减少花括号的数量:

trait Before {
  private var _x = 0
  def x: Int = _x
  def x_=(value: Int) { _x = value }
}

对比

trait After {
  private var _x = 0
  def x: Int = _x
  def x_=(value: Int): Unit = _x = value  // if double = confuses you, use new line?
}

我发现很多情况下,代码块以ifmatchsynchronized块或生成future的表达式、集合map表达式等开始,这些情况下去掉花括号会更好:

trait Before {
  def connect()(implicit tx: Tx) {
    values.foreach { case (x, _) =>
      x.changed += this
    }
  }
}

trait After {
  def connect()(implicit tx: Tx): Unit =
    values.foreach { case (x, _) =>
      x.changed += this
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接