4

Scala-style-guide は、使用時に期待される戻り値の型を常に明示的に定義することを提案しますUnit:

メソッドは、次のパターンに従って宣言する必要があります。

def foo(bar: Baz): Bin = expr

このルールの唯一の例外は、Unit を返すメソッドです。そのようなメソッドは、Scala のシンタックス シュガーを使用して、誤って戻り値の型を混乱させないようにする必要があります。

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

1 に答える 1

2

コメンテーターが指摘したように、Martin Odersky はリンクされた基調講演でこれについて議論しています。もちろん、「いつ…すべきか」が示すように、これは最終的に文体の問題なので、意見を述べることができるだけです。

2 つのこと: (1) タイプ yes/no、および (2) プロシージャ構文 yes/no。


(1) 明らかに純粋な API (実装なし) では、戻り値の型を指定する必要があります。これを、同時にAPIである任意のメソッド実装に拡張します。つまり、メソッドがトレイトを実装していない場合 (この場合、戻り値の型が異なるとコンパイラはエラーを返します)、メソッドに注釈を付ける必要があります。プライベート メソッドとローカルメソッドの戻り値の型を推測しても問題ありませんが、一見しただけでは型を判断するのが難しい場合や、(たとえば、再帰的なメソッド呼び出しで) 強制される場合を除きます。また、戻り値の型を明示的に与えるとコンパイルが速くなるとも言われています。

「簡単な」戻り値の型を持つ短いメソッドがある場合、推論は問題ないと思います。元。

trait Foo {
  def sqrt(d: Double) = math.sqrt(d)

  def toString = "Foo"

  def bar = new Bar(123)
}

math.sqrt(しかし、が a を返すことは明らかではないかもしれないと主張する人がすでにいるかもしれません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本体が、 pattern 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
    }
}
于 2013-08-04T22:10:54.543 に答える