Подтвердить что ты не робот

Scala - приоритет метода

Я новичок в Scala. Интересно, можно ли определить некоторый приоритет вызовами метода. Например, если у меня есть цепочка вызовов методов:

someObject method1 param1 method2 param2 method3 param3

может быть эквивалентно следующему:

someObject.method1(param1).method2(param2.method3(param3))

или

someObject method1 param1 method2 (param2 method3 param3)

Итак, я хочу, чтобы метод3 имел приоритет над методом2...

Причина, по которой я хочу сделать это, - это то, что я хочу разработать DSL, поэтому я хочу как можно больше избегать использования точек и скобок. Если вы, ребята, найдете другое решение для меня, не стесняйтесь, дайте мне знать.

4b9b3361

Ответ 1

Вам нужно будет использовать методы со специальными символами оператора, чтобы влиять на приоритет, как это подразумевает Томаш. Отчасти это связано с тем, что многие из Scala DSL активно используют операторов. Также почему некоторые DSL трудно читать, если вы не работаете с ними ежедневно.

Данный метод с использованием только букв, подчеркивания и цифр - вы не сможете влиять на вещи, вот что я собрал для себя после прочтения спецификации:

  • Любой метод, который принимает один параметр, может использоваться в качестве инфиксного оператора: a.m(b) можно записать a m b.
  • Любой метод, который не требует параметра, может использоваться как постфиксный оператор: a.m можно записать a m.

  • Операторы Postfix имеют более низкий приоритет, чем операторы infix, поэтому foo bar baz означает foo.bar(baz), а foo bar baz bam означает (foo.bar(baz)).bam и foo bar baz bam bim означает (foo.bar(baz)).bam(bim).

Поэтому, не зная вообще, что такое подписи вашего метода, следующий код (потому что он все буквенно-цифровой):

someObject method1 param1 method2 param2 method3 param3

будет анализироваться как:

someObject.method1(param1).method2(param2).method3(param3)

Если вы переименуете method3 в |*| или +:+ или любой другой оператор имеет смысл, вы можете достичь того, чего хотите:

someObject method1 param1  method2 param2 |*| param3
// same as
someObject.method1(param1).method2(param2.|*|(param3))

Например, чтобы увидеть разницу:

implicit def pimp(s:String) = new {
    def |*|(t:String) = t + s
    def switch(t:String) = t + s 
}

scala> "someObject" concat "param1" concat "param2" |*| "param3"
res2: java.lang.String = someObjectparam1param3param2

scala> "someObject" concat "param1" concat "param2" switch "param3"
res3: java.lang.String = param3someObjectparam1param2

Ответ 2

Это поведение определено в главе 6.12.3 Операции Infix в Scala Language Specification.

Короче: методы вызываются слева направо по умолчанию с некоторыми исключениями. Эти исключения были введены только для поддержки приоритетов математических операторов. Поэтому, когда у вас есть две функции с именем * и +:

a + b * c

Это всегда будет переведено на:

a.+(b.*(c))

Здесь первое имя функции управляет приоритетом. Однако для обычных функций вы не можете контролировать порядок. Подумайте об этом - это на самом деле вызовет хаос и ужасно неподдерживаемый код.

См. также (не совсем дублировать?): приоритет оператора в Scala.