什么时候Scala方法def应该使用显式定义的返回类型?

时间:2013-08-04 15:40:57

标签: scala coding-style

Scala-style-guide建议在使用Unit时始终显式定义返回类型expect:

  

应根据以下模式声明方法:

def foo(bar: Baz): Bin = expr
     

此规则的唯一例外是返回Unit的方法。这样   方法应该使用Scala的语法糖来避免意外   令人困惑的退货类型:

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

1 个答案:

答案 0 :(得分:1)

正如评论家指出的那样,Martin Odersky在链接的主题演讲中对此进行了讨论。当然,正如“什么时候......”所表明的那样,这最终是一个风格问题,所以人们只能发表意见。

两件事:(1)类型是/否,以及(2)程序语法是/否。


(1)显然,对于纯API(没有实现),您必须指定返回类型。我会将此扩展到任何方法实现,同时 API 。即,如果您的方法没有实现特征 - 在这种情况下编译器会在返回类型不同时给出错误 - 您应该注释该方法。 私有和本地方法可以推断出返回类型,除非您发现很难在第一眼看出类型,或者您被迫(例如在递归方法调用中)。还有人说,当你给出明确的返回类型时,编译是更快

如果您使用“easy”返回类型的简短方法,我认为推理很好。实施例

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?
}

我发现很多情况下身体都以if,模式matchsynchronized阻止或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
    }
}