2011-09-29 104 views
16

我是斯卡拉新手。我想知道是否可以用方法调用来定义一些优先级。举例来说,如果我有方法的调用链:斯卡拉 - 方法优先

someObject method1 param1 method2 param2 method3 param3 

可以将此等同于以下内容:

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

someObject method1 param1 method2 (param2 method3 param3) 

所以我想方法3到超过优先方法2 ...

我想这样做的原因是我想开发一个DSL,所以我想避免使用点和圆括号尽可能多。如果你们为我找到了另一种解决方案,请随时告诉我。

+2

您可能需要阅读http://www.manning.com/ghosh/(在行动中的DSL),因为这将有助于解释很大。他涵盖了Ruby,Scala(主要是Scala),Clojure和Groovy。 –

回答

3

此行为在的章节6.12.3 Infix Operations中定义了Scala语言规范

简而言之:默认情况下,方法从左到右被调用,但有一些例外。这些例外仅用于支持数学运算符的优先级。所以,当你有一个名为*+两个功能:

a + b * c 

这将始终被翻译成:

a.+(b.*(c)) 

这里函数的名字控制的优先级。但对于普通功能,您无法控制订单。想一想 - 这实际上会造成破坏性的和非常难以维护的代码。

另请参见(不完全相同?):Operator precedence in Scala

+1

请注意,该规范是错误的 - 请参阅http://article.gmane.org/gmane.comp.lang.scala/24402和http://stackoverflow.com/questions/7022207/why-scala-changed-relative-precedence -of关系-VS平等的运营商 - COMPAR/7022704#7022704。 – huynhjl

11

您必须使用具有特殊运算符字符的方法来影响Tomasz所暗示的优先顺序。这就是为什么许多Scala DSL会大量使用运营商的原因。此外,为什么一些DSL很难阅读,如果你不每天与他们合作。

鉴于方法只使用字母,下划线和数字 - 你将无法影响的事情,这里是我放在一起为自己读取规格后:

  • 任何这需要一个单一的方法参数可以用作中缀运算符:a.m(b)可以写成a m b
  • 任何不需要参数的方法都可以用作后缀运算符:a.m可以编写为a m

  • 后缀运算符具有比中缀运算符的优先级低,所以foo bar baz意味着foo.bar(baz)foo bar baz bam装置(foo.bar(baz)).bamfoo 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 
+0

你的回答非常有帮助:)。但我真的希望我的DSL易于理解和直观地使用,所以我不能使用非字母数字字符的方法。有没有方法混合字母和非字母数字字符的方法名? – Peter

+0

@Peter,不是有用的。您可以命名一个方法'foo_?'或'foo _#%^',但是它是方法的第一个字母,它决定了优先级,如果方法名以一个操作符开始,它必须完全由操作符组成。请注意,如果您使用特殊字符,DSL仍然很直观,但您需要小心。例如,我发现大多数http://www.scala-lang.org/api/current/scala/sys/process/ProcessBuilder.html中的操作符都易于记忆,而我很难用http:// dispatch .databinder.net /双+处理程序+ +是更好+比+ One.html。 – huynhjl