9

与えられた:

def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") } 

私はそれを呼び出すことができます:

save("test")(true) -> running f
save("test")(false) -> not running f
save(throw new RuntimeException("boom!"))(false) -> not running f
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown

部分適用による興味深い動作は次のとおりです。

save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected
save(throw new RuntimeException("boom!")) _ -> exception thrown

コードブロックは、関数として渡されることなく、すぐに評価されます。上記の2つのステートメントの違いは何ですか?

4

2 に答える 2

3

最初のケース

save(throw new RuntimeException("boom!")) _ 

「Scala Reference」 (§6.7) によると、引数リストの代わりに末尾のアンダースコアが使用され、式は次のように変換されます。

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))

の最初の引数def saveはすぐに評価されます。

e がメソッド型である場合、または e が名前による呼び出しパラメーターである場合、式 e _ は整形式です。e がパラメーターを持つメソッドの場合、e _ は、eta 展開 (§6.26.5) によって関数型に変換された e を表します。e がパラメーターなしのメソッドまたは型 =>T の名前による呼び出しパラメーターである場合、 e _ は型 () => T の関数を表し、空のパラメーターリスト () に適用されたときに e を評価します。

期待どおりに動作させるには、いくつかの変更が必要です。

scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") }
save: (f: () => Any)(run: Boolean)Unit

scala> val f = save(() => throw new RuntimeException("boom!")) _
f: (Boolean) => Unit = <function1>

scala> f(true)
running f
java.lang.RuntimeException: boom!
        at $anonfun$1.apply(<console>:6)

2番目のケース

save(throw new RuntimeException("boom!"))(_)

「Scala Reference」 (§6.23) によると、引数の代わりにプレースホルダーを使用すると、式は次のように変換されます。

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_)
于 2011-02-07T09:31:39.970 に答える
0

eta 展開での名前による呼び出しパラメータの動作は、現在レビュー中です。このバグを参照してください。save(throw new RuntimeException("boom!")) _2.10 の最近のナイトリー ビルドでは、コードは期待どおりに動作します (つまり、行は例外をスローせずに関数を返します)。発売まで残っているか見てみよう!

名前による呼び出しを含まない eta 展開の一般的なケースに関する関連する質問については、この質問も参照してください。

于 2012-05-31T21:42:48.207 に答える