2

私はすでにScalaでアンダースコアのすべての用途は何ですか?この質問はすでに聞かれていると確信していますが、Scala に関する他の 17000 の質問をすべて調べることはできません。

Foreach には奇妙な動作があり、Placeholder は役に立ちませんが、まだ隠された機能のようです:

scala> val is = (1 to 5) toList
is: List[Int] = List(1, 2, 3, 4, 5)

scala> is foreach { i => println("Hi.") ; Console println 2 * i }
Hi.
2
Hi.
4
Hi.
6
Hi.
8
Hi.
10

scala> is foreach { println("Hi.") ; Console println 2 * _ }
Hi.
2
4
6
8
10

誰かが私に違いを教えてくれますか?

熱意が爆発したと感じたら、次のことを試してください。

scala> is foreach { i => println("Hi!") ; Console println 2 * i }
java.lang.IllegalArgumentException: !") ; Console println 2 * i }: event not found

次に、この回答を参照してください。 そして、はい、それは本当に起こりました。

4

2 に答える 2

7

プレースホルダー構文は、ブロック全体ではなく、1 つの式で機能するため、例は次のように解釈されます。{ println("Hi."); i => Console println 2 * i }

于 2013-07-15T06:40:01.303 に答える
3

Landei は正しい答えを持っていると思いますが、完全には展開されていません。最後に始めましょう:

scala> Console println 2 * _
<console>:8: error: missing parameter type for expanded function
((x$1) => Console.println(2.$times(x$1)))
              Console println 2 * _
                                  ^

わかりましたので、Console println 2 * _明示的な eta 展開を使用して関数を作成しようとしていることがわかりますが、戻りパラメーターの型がわからないため作成できません。

それでは、関数を返すコード ブロックを試してみましょう。

scala> { println("Hi"); (i: Int) => i*5 }
Hi
res1: Int => Int = <function1>

したがって、すべての場合と同様に、ブロック全体 ( のような副作用のあるステートメントを含む) を実行し、println関数である戻り値を返します。

Landei が言ったように、プレースホルダー構文は 1 つの (単純な) 式の 1 つの引数に対してのみ機能し、2 番目のケースでは、単純な式ではなくブロック式 (2 つの単純な式で構成される) があります。したがって、プレースホルダー構文は使用していません。関数を作成しています。そして、コードブロックでそれを行います:

is foreach { println("Hi.") ; Console println 2 * _ }

これは、関数の引数から始めないため、単純なパラメーターとして解釈されますが、ほとんどすべてのコンテキスト (引数リストを含む) で単純な式(x)をブロック式に置き換えることができます{ stuff; x }。したがって、次のように考えることができます

is foreach ({ println("Hi.") ; Console.println 2 * _ })

これで、型推論器は戻り値の型がどうあるべきかを認識したので、"Hi" を出力して関数を作成するコード ブロックを実行し、その関数を (最初に 1 回だけ!) に渡しますforeach。型推論器が行全体を調べて型を把握できる場合、これは次のようになります。

val temp = { println("Hi."); Console.println 2 * _ }
is foreach (temp)
于 2013-07-15T07:51:44.383 に答える