2011-09-29 120 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