Warum kann ich nicht mehrere Scala-Infix-Methodenaufrufe verketten?
-
29-10-2019 - |
Frage
Ich arbeite an einem DSL und habe ein Problem mit der Verwendung von Methoden als Infix-Operatoren in einer Kette.Ich werde nur versuchen, es mit etwas Code zu erklären.Ich habe ein Merkmal Term
und Fallklassen Literal
und Variable
, die es erweitern.Ich möchte mit einigen Operatoren eine Liste von Terminstanzen erstellen.
case class Expr(val terms: List[Term]) {
def +(v: String) = Expr(Literal(v) :: terms)
def -->(func: List[String] => List[String]) = terms match {
case Literal(v) :: ts => Expr(Variable(v, func) :: ts)
case _ => throw new Exception("Can only apply function on literal")
}
}
object foo {
def bar(name: String) = Expr(Literal(name) :: Nil)
}
// some functions
val one = ...
val all = ...
// works
foo bar "x"
// res1: Expr = Expr(List(Literal(x)))
// works not
foo bar "x" --> all
// error: value --> is not a member of java.lang.String
// works
(foo bar "x") --> all
// res1: Expr = Expr(List(Variable(x,<function1>)))
Ich würde erwarten, dass dies dem foo.bar("x").-->(all)
entspricht, aber der Interpreter scheint ihn als foo.bar("x".-->(all))
zu betrachten.
Lösung
Hier finden Sie die Operator-Priorität :
Nach der ersten Antwort hat -
eine höhere Priorität als Buchstaben.Der Compiler gruppiert den Ausdruck also wie folgt:
foo bar ("x" --> all)
Wenn Sie -->
durch etwas mit niedrigerer Priorität (z. B. Buchstaben) ersetzen, sollte es kompiliert werden.Zum Beispiel:
foo bar "x" to all
Sie können auch einen Operator mit höherer Priorität anstelle von bar
wählen.So etwas wie ~~>
wird es tun, weil ~
ein Sonderzeichen ist und höchste Priorität hat:
foo ~~> "x" --> all