7

Ich verwende _ als Platzhalter zum Erstellen anonymer Funktion, und das Problem ist, ich kann nicht vorhersagen, wie Scala meinen Code transformieren wird. Genauer gesagt bestimmt es fälschlicherweise, wie groß die anonyme Funktion sein soll.Welche Regeln gelten für Unterstreichungen, um anonyme Funktionen zu definieren?

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

Mit -Xprint:typer Ich sehe Scala die ersten in „eine große anonyme Funktion“ verwandelt:

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

der bearbeitete 2. 3. sind rechts Transformation in dem, was ich will.

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

Warum das? Was ist die Regel ?

Antwort

8

Einfache Regeln den Umfang der Unterstrich zu bestimmen:

  1. Wenn der Unterstrich ist ein Argument, ein Verfahren, dann wird der Umfang außerhalb sein, dass Verfahren, sonst jeweils die folgenden Regeln;
  2. Wenn der Unterstrich innerhalb eines durch() oder {} abgegrenzten Ausdrucks liegt, wird das innerste solche Begrenzungszeichen verwendet, das den Unterstrich enthält.
  3. Bei sonst gleichen Bedingungen wird der größtmögliche Ausdruck verwendet.

also von der Regel # 1, statt println((x: Int) => x) wird der Umfang außerhalb platziert werden (einschließlich) println.

Nach Regel # 2 haben die letzten beiden Beispiele die durch Klammern begrenzte Funktion, also (x => println(x: Int)).

Nach Regel # 3 ist das erste Beispiel der gesamte Ausdruck, da es keine begrenzenden Klammern gibt.

4

Ich glaube, Mr. Sobral's Antwort ist falsch. Die eigentlichen Regeln finden Sie in Scala Language Reference, Abschnitt 6.23, Unterüberschrift "Platzhaltersyntax für anonyme Funktionen."

Die einzige Regel ist, dass der innerste Ausdruck, der den Unterstrich richtig enthält, den Umfang der anonymen Funktion definiert. Das bedeutet, dass die ersten beiden Regeln von Herrn Sobral korrekt sind, weil ein Methodenaufruf ein Ausdruck ist und die Klammerung eines Ausdrucks seine Bedeutung nicht ändert. Aber die dritte Regel ist das Gegenteil der Wahrheit: alle anderen Dinge sind gleich, der kleinste Ausdruck, der Sinn macht, wird verwendet.

Leider ist meine Erklärung für das Verhalten, das Herr Laskowski für sein erstes Beispiel beobachtet hat, etwas umständlich und spekulativ. Wenn

ist in der Scala Read-Eval-Print-Schleife eingegeben.Die Fehlermeldung lautet:

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

Wenn Sie variieren das Beispiel ein kleines bisschen:

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

die Fehlermeldung leichter ist, einen Sinn zu geben -

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) 
        ^

Um zu verstehen, was ein etwas besser, rufen Sie scala so: scala -Xprint:parser, die, nach jedem Ausdruck vom Benutzer eingegeben wird, bewirkt, dass der Ausdruck, der durch den Parser ausgedruckt wird, gedruckt wird. (Zusammen mit einer Menge Müll, die ich weglassen.) Für Laskowski erstes Beispiel wird der Ausdruck durch den Parser zu verstehen ist

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

Für das zweite Beispiel der Version des Parsers ist

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

Offensichtlich wird die Bereichsregel angewendet, bevor die Ausdrucksstruktur vollständig ausgearbeitet wurde. In beiden Fällen rät der Parser, dass der kleinste Ausdruck bei List beginnt, auch wenn die Parens erst eingefügt werden, wenn sie nicht mehr wahr sind. Im zweiten Beispiel wird zusätzlich zu dieser Annahme davon ausgegangen, dass println ein Bezeichner ist. foreach println ist eine Kette von Methoden, von denen die erste keine Argumente hat. Der Fehler bei foreach wird dann vor dem Fehler bei println abgefangen und verdeckt. Der Fehler bei println ist, dass das Ergebnis Unit lautet und foreach eine Funktion erfordert. Sobald Sie den Syntaxbaum sehen, ist es leicht zu sehen, dass dies korrekt ist, aber es ist mir nicht klar, warum der Syntaxbaum das ist, was er ist.