3

我很難理解何時可以或不能省略方括號和/或句點,以及如何這與_相互作用。命名參數vs _,點符號與中綴操作,在Scala中使用高級函數時的捲曲與圓括號

我不得不這樣做的特例是

val x: X = ??? 
val xss: List[List[X]] = ??? 
xss map x :: _ //this doesn't compile 
xss map _.::(x) //this is the same as the above (and thus doesn't compile) 

上述兩個似乎是相同的xss.map(_).::(x)

xss map (x :: _) //this works as expected 
xss map {x :: _} //this does the same thing as the above 

同時,下面還失敗:

xss.map xs => x :: xs //';' expected but '=>' found. 
xss.map x :: _ //missing arguments for method map in class List; follow this method with `_' if you want to treat it as a partially applied function 
//so when I try following the method with _, I get my favourite: 
xss.map _ x :: _ //Cannot construct a collection of type That with elements of type B based on a collection of type List[List[Main.X]] 
//as opposed to 
xss map _ x :: _ //missing parameter type for expanded function ((x$1) => xss.map(x$1).x(($colon$colon: (() => <empty>)))) 

權現在,我經常玩「切換符號,直到它編譯」我認爲是次優編程策略。這一切如何工作?

+2

您是否看到http://stackoverflow.com/questions/2173373/scala-foreach-strange-behaviour? – sschaef 2014-10-18 11:15:12

+0

還沒有,謝謝。看着。 – Martijn 2014-10-18 11:18:45

+1

這應該有助於解決掉圓括號/圓點的問題:http://stackoverflow.com/questions/1181533/what-are-the-precise-rules-for-when-you-can-omit-parenthesis-點 - 大括號 - f – sschaef 2014-10-18 11:23:30

回答

2

首先,我們需要區分xss.map(f)xss map f。根據Scala Documentation,採用單個參數的任何方法均可用作中綴運算符。

實際上map method in List是這些方法之一。忽略完整的簽名,並且它是從TraversableLike繼承的事實,簽名如下:

final def map[B](f: (A) ⇒ B): List[B] 

所以它需要一個參數,即f,這是A => B類型的函數。所以,如果你有一個function value定義爲

val mySize = (xs:List[Int]) => xs.size 

你可以選擇

xss.map(mySize) 

xss map mySize 

之間 這是偏好的問題,但根據Scala Style Guide,這種情況下,後者是首選的,除非它是複雜表達式的一部分,最好堅持點表示法。

請注意,如果您選擇使用點符號,則始終需要使用括號限定功能應用程序!這就是爲什麼以下都不能成功編譯的原因。

xss.map xs => x :: xs // Won't compile 
xss.map x :: _ // Won't compile 
xss.map _ x :: _ // Won't compile 

但大部分的時間,而不是通過一個函數值,你需要傳遞一個function literal(又名anonymous function)。在這種情況下,如果使用點符號,則需要類似xss.map(_.size)。但是如果使用中綴表示法,這將是一個優先問題。

例如

xss map x :: _ // Won't compile! 

不會因爲運算符優先級的工作。所以你需要使用括號來解析xss map (x :: _)編譯器的情況。

使用花括號代替括號有一個非常明確和簡單的規則。同樣,只有一個參數的任何函數都可以用花括號代替括號來應用,無論是中綴還是點符號。所以下面的語句將被編譯。

xss.map{x :: _} 
xss map {x :: _} 

爲避免混淆,您可以從點符號和顯式類型參數開始。在編譯之後 - 也許爲你的代碼編寫一些單元測試 - 你可以通過刪除不必要的類型,使用中綴表示法來重構代碼,並且在有意義的地方使用花括號代替括號。

爲此,您可以參考Scala Style GuideMartin Odersky's talk in Scala Days 2013,它涉及到Scala編碼風格。此外,您總是可以向IDE尋求幫助以重構代碼,使其更加簡潔。

+0

偉大的答案,謝謝。至於要求Eclipse插件重構我的代碼 - 根據我的經驗,結果很糟糕,儘管我對intellij – Martijn 2014-10-19 11:17:07

+0

感興趣,我用[IntelliJ IDEA Scala插件](http://plugins.jetbrains.com/插件/?ID = 1347)。它會自動檢測可能更簡單的部分代碼。例如,如果您編寫'xss map(mySize)',它會建議刪除圓括號。即使你編寫'xss map(mySize(_))',它建議首先刪除不必要的'_',然後在刪除之後建議刪除括號。它足夠聰明,可以檢測大多數常見問題和代碼異味。 – 2014-10-19 11:23:54