- Scala編程(第5版)
- (德)馬丁·奧德斯基等
- 1200字
- 2022-05-06 15:51:42
5.9 操作符優先級和結合律
操作符優先級決定了表達式中的哪些部分會先于其他部分被求值。例如,表達式2 + 2 * 7經求值得到16而不是28,因為操作符*的優先級高于+。因此,表達式的乘法部分先于加法部分被求值。當然,也可以在表達式中用圓括號來澄清求值順序,或者覆蓋默認的優先級。例如,如果想要上述表達式經求值得到28,則可以像這樣來寫:

Scala并不是真的有操作符,操作符僅僅是用操作符表示法使用方法的一種方式。你可能會好奇操作符優先級的工作原理是什么。Scala根據操作符表示法中使用的方法名的首個字母來判定優先級(這個規則有一個例外,會在后面講到)。舉例來說,如果方法名以*開頭,它將擁有比以+開頭的方法更高的優先級。因此2 + 2 * 7會被當作2 + (2 * 7)求值。同理,a +++ b *** c(其中a、b、c是變量,+++和***是方法)將被當作a +++ (b *** c)求值,因為***方法比+++方法的優先級更高。
表5.3顯示了方法首字符的優先級順序,且依次遞減,位于同一行的擁有同樣的優先級。
表5.3 操作符優先級

在表格中某個字符的優先級越高,則以這個字符開頭的方法就擁有更高的優先級。如下例子展示了優先級的影響:

<<方法以字符<開頭,在表5.3中,<出現在字符+的下方,因此表達式會先調用+方法,再調用<<方法,即2 << (2 + 2)。按數學方法計算,2 + 2得4,2 << 4得32。如果將這兩個操作交換一下次序,將會得到不同的結果:

由于方法的首字符與前一例一樣,方法將會按照相同的順序調用。先是+方法,再是<<方法。因此2 + 2得4,而4 << 2得16。
前面提到過,優先級規則的一個例外是賦值操作符(assignment operator)。這些操作符以等號(=)結尾,且不是比較操作符(<=、>=、==或!=),它們的優先級與簡單的賦值(=)擁有的優先級一樣。也就是說,比其他任何操作符都低。例如:

與如下代碼是一樣的:

因為*=被歸類為賦值操作符,而賦值操作符的優先級比+低,盡管它的首字符是*,看上去應該比+的優先級更高。
當多個同等優先級的操作符并排在一起時,操作符的結合律決定了操作符的分組。Scala中操作符的結合律由操作符的最后一個字符決定。正如我們在第3章提到的,任何以':'字符結尾的方法都是在它右側的操作元上調用,并傳入左側的操作元的。以任何其他字符結尾的方法則相反:這些方法是在左側的操作元上調用,并傳入右側的操作元的。因此a * b交出a.*(b),而a ::: b將交出b.:::(a)。
不過,無論操作符的結合律是哪一種,它的操作元都是從左到右被求值的。因此,如果a不是一個簡單的引用某個不可變值的表達式,則更準確地說,a ::: b會被當作如下的代碼塊:

在這個代碼塊中,a仍然是先于b被求值的,然后這個求值結果被作為操作元傳入b的:::方法。
這個結合律規則在相同優先級的操作符并排出現時也有相應的作用。如果方法名以':'結尾,它們會被從右向左依次分組;否則,它們會被從左向右依次分組。例如,a ::: b ::: c 被當作a ::: (b ::: c),而a * b * c則被當作(a * b) * c。
操作符優先級是Scala語言的一部分,在使用時不需要過于擔心。話雖如此,一個好的編碼風格可以清晰地表達出什么操作符被用在什么表達式上。也許你可以唯一真正放心讓其他程序員能夠不查文檔就能知道的優先級規則是,乘法類的操作符(*、/、%)比加法類的操作符(+、-)擁有更高的優先級。因此,雖然a + b << c在不加任何圓括號的情況下可以交出你想要的結果,但是把表達式寫成(a + b) << c會帶來額外的清晰效果,也可能會減少別人用操作符表示法對你表達不滿的頻率,比如,憤懣地大聲說這是“bills !*&^%~ code!”。[11]