web-dev-qa-db-ja.com

Scalaのdeffoo = {}とdeffoo()= {}の違いは何ですか?

Scalaで関数を定義するための次の構成を考えると、違いは何か、そしてその意味は何であるかを説明できますか?

def foo = {}

vs.

def foo() = {}

更新

迅速な対応に感謝します。これらは素晴らしいです。私に残っている唯一の質問は:

括弧を省略しても、関数を渡す方法はありますか?これは私がreplで得るものです:

scala> def foo = {}
foo: Unit

scala> def baz() = {}
baz: ()Unit

scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit

scala> test(foo)
<console>:10: error: type mismatch;
 found   : Unit
 required: () => Unit
              test(foo)
                   ^

scala> test(baz)
res1: () => Unit = <function0>

更新2012-09-14

これが私が気づいたいくつかの同様の質問です:

  1. 括弧付きと括弧なしの関数の違い
  2. 引数のないScalaメソッド
54
Jay Taylor

定義に括弧を含める場合は、メソッドを呼び出すときに括弧をオプションで省略できます。定義でそれらを省略すると、メソッドを呼び出すときにそれらを使用できなくなります。

_scala> def foo() {}
foo: ()Unit

scala> def bar {}
bar: Unit

scala> foo

scala> bar()
<console>:12: error: Unit does not take parameters
       bar()
          ^
_

さらに、高階関数で同様のことを行うことができます。

_scala> def baz(f: () => Unit) {}
baz: (f: () => Unit)Unit

scala> def bat(f: => Unit) {}
bat: (f: => Unit)Unit

scala> baz(foo)    

scala> baz(bar)
<console>:13: error: type mismatch;
 found   : Unit
 required: () => Unit
       baz(bar)
           ^
scala> bat(foo)

scala> bat(bar)  // both ok
_

ここで、bazfoo()のみを取り、barは取りません。これを何に使うのか、わかりません。しかし、それはタイプが異なることを示しています。

私が投稿した私の答えをコピーさせてください 重複した質問

A Scala 0-アリティのメソッドは括弧付きまたは括弧なしで定義できます()。これは、後でvalとして実装できる、メソッドがない場合とは対照的に、メソッドに何らかの副作用(std outへの出力やデータの破棄など)があることをユーザーに通知するために使用されます。

Scalaでのプログラミング を参照してください:

このようなパラメーターのない方法は、Scalaでは非常に一般的です。対照的に、def height():Intなどの空の括弧で定義されたメソッドは、empty-parenメソッドと呼ばれます。推奨される規則は、パラメーターがなく、メソッドが含まれているオブジェクトのフィールドを読み取ることによってのみ可変状態にアクセスする場合は常にパラメーターなしのメソッドを使用することです(特に、可変状態は変更されません)。

この規則は、統一アクセスの原則をサポートしています[...]

要約すると、Scalaのスタイルでは、パラメーターを受け取らず、副作用のないメソッドをパラメーターなしのメソッドとして定義することをお勧めします。つまり、空の括弧を省略します。一方、絶対にしないでください。そのメソッドの呼び出しはフィールド選択のように見えるため、括弧なしで副作用があるメソッドを定義します。

38
Eugene Yokota

2番目の質問に答えるには、_を追加するだけです。

scala> def foo = println("foo!")
foo: Unit

scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit

scala> test(foo _)
res10: () => Unit = <function0>

scala> test(foo _)()
foo!

scala>            
5
aij

常に次のような関数で定義を開始することをお勧めします。

def bar {}

そして、あなたが強制された場合にのみ、それを次のように変更する必要があります。

def bar() {}

理由:これら2つの関数を可能な使用法の観点から考えてみましょう。それらをどのように情報提供することができ、どこに渡すことができるか。

私はこれを関数とはまったく呼びません:

def bar {}

次のように呼び出すことができます。

bar

ただし、関数としてではありません。

bar()

名前による呼び出しパラメーターを使用して高階関数を定義するときに、このバーを使用できます。

def bat(f: => Unit) {
    f //you must not use (), it will fail f()
}

=> Unit-は関数ではないことを覚えておく必要があります。サンクを関数値として処理して保存または渡すことができない限り、サンクを関数であるかのように操作することは絶対にできません。実際の引数式(任意の数)の評価のみをトリガーできます。 Scala:中括弧の間のコードブロックとして関数を渡す

()で定義された関数は、使用範囲が広くなります。 barと同じコンテキストで、正確に使用できます。

def foo() = {}
//invokation:
foo
//or as a function:
foo()

これは、名前による呼び出しパラメーターを使用して関数に渡すことができます。

bat(foo)

さらに、高階関数を定義すると、名前による呼び出しのパマメーターではなく、実際の関数が受け入れられます。

def baz(f: () => Unit) {}

foobazに渡すこともできます。

baz(foo)

ご覧のとおり、fooのような標準関数の使用範囲は広くなっています。ただし、()なしで定義された関数に加えて、名前による呼び出しパラメーターを受け入れる高階関数を定義する場合は、より明確な構文を使用できます。

より優れた、より読みやすいコードをアーカイブしようとしない場合、または名前による呼び出しパラメーターで定義された関数と実際の関数で定義された関数の両方にコードを渡す機能が必要な場合は、標準のものとして機能します:

def foo() {}

より明確で読みやすいコードを記述したい場合で、関数に副作用がない場合は、関数を次のように定義します。

def bar {}

PLUSは、関数ではなく、名前による呼び出しパラメーターを受け入れるように高階関数を定義しようとします。強制された場合のみ、この場合のみ前のオプションを使用してください。

0
Alexandr