8

無名関数を作成するためのプレースホルダーとして使用_していますが、問題は、Scala がコードをどのように変換するかを予測できないことです。より正確には、私が望む無名関数の「大きさ」を誤って判断します。

 List(1,2,3) foreach println(_:Int)   //error !
 List(1,2,3) foreach (println(_:Int)) //work
 List(1,2,3) foreach(println(_:Int))  //work

I can see Scalaを使用-Xprint:typerすると、最初の関数が「大きな無名関数」に変換されます。

x$1 => List(1,2,3) foreach(println(x$1:Int))

働いた 2 番目 3 番目は、私が望むものに正しく変換されます。

... foreach (x$1 => println(x$1:Int)) 

なぜこれ?ルールは何ですか?

4

2 に答える 2

10

アンダースコアの範囲を決定する簡単なルール:

  1. アンダースコアがメソッドへの引数である場合、スコープはそのメソッドの外側になります。それ以外の場合は、以下の規則に従います。
  2. アンダースコアが () または {} で区切られた式の中にある場合、アンダースコアを含む最も内側の区切り文字が使用されます。
  3. 他のすべての条件が等しい場合、可能な最大の式が使用されます。

したがって、ルール 1 により、 の代わりにprintln((x: Int) => x)、スコープは の外側 (含む) に配置されprintlnます。

ルール 2 により、後者の 2 つの例では関数が括弧で区切られているため、(x => println(x: Int)).

ルール #3 により、区切り括弧がないため、最初の例は式全体になります。

于 2015-01-24T13:38:38.747 に答える
4

ソブラルさんの答えは間違っていると思います。実際の規則は、Scala 言語リファレンスのセクション 6.23 のサブヘッド「無名関数のプレースホルダー構文」にあります。

唯一のルールは、アンダースコアを適切に含む最も内側の式が無名関数のスコープを定義することです。つまり、ソブラル氏の最初の 2 つの規則は正しいということです。なぜなら、メソッド呼び出しは式であり、式を括弧で囲んでもその意味は変わらないからです。しかし、3 番目の規則は真実の反対です。他のすべての条件が等しい場合、意味のある最小の式が使用されます。

残念ながら、Laskowski 氏が最初の例で観察した動作についての私の説明は、少し複雑で推測にすぎません。いつ

List(1,2,3) foreach println(_:Int)

Scala の read-eval-print ループで入力されます。エラーメッセージは次のとおりです。

error: type mismatch;
 found   : Unit
 required: Int => ?
              List(1,2,3) foreach println(_:Int)
                                         ^

例を少し変更すると、次のようになります。

List(1,2,3).foreach println(_:Int)

エラーメッセージは理解しやすい -

error: missing arguments for method foreach in class List;
follow this method with `_' if you want to treat it as a partially applied function
          List(1,2,3).foreach println(_:Int)
                      ^

物事をもう少しよく理解するには、scalathis:を呼び出します。scala -Xprint:parserこれは、ユーザーがすべての式を入力した後、パーサーによって肉付けされた式を出力します。(省略しますが、ゴミがたくさんあります。) Laskowski の最初の例では、パーサーが理解できる式は次のとおりです。

((x$1: Int) => List(1, 2, 3).foreach(println((x$1: Int))))

2 番目の例では、パーサーのバージョンは

((x$1: Int) => List(1, 2, 3).foreach.println((x$1: Int)))

明らかに、式の構造が完全に肉付けされる前に、スコープ ルールが適用されます。どちらの場合も、パーサーは最小の式が List で始まると推測しますが、括弧が挿入されるとそれは正しくなくなります。2 番目の例では、その仮定に加えて、printlnは識別子でforeach printlnあるため、 はメソッドのチェーンであり、最初のメソッドには引数がないと仮定しています。でのエラーforeachは、エラーでのエラーの前に捕捉されprintln、それをマスクします。のエラーprintlnは、その結果が Unit でforeachあり、関数が必要であるということです。解析ツリーを見れば、これが正しいことは簡単にわかりますが、(私には) なぜ解析ツリーが何であるかは明確ではありません。

于 2015-08-04T17:17:42.167 に答える