2016年4月11日 星期一

[Scala 小學堂] Scala Gossic : 起步走 - 資料、變數、操作 (操作順序與關聯)

轉載自 這裡 
前言 : 
Scala 是一個可直譯、編譯、靜態、運行於 JVM 之上、可與 Java 互操作、融合物件導向編程特性與函式編程風格的程式語言. 從一些簡單的語法開始,了解 Scala 的許多特性,所以就算是起步走,東西也夠多了. 簡單的小程式可以使用 scala 指令,編譯的事就交給 scalac,編譯想快點就用 fsc. (Scala 官網), 所有的東西都是物件,所有的操作都是方法. 

操作順序與關聯 : 
+、 -、*、/... 這些一般語言所謂的運算子,在 Scala 中其實是方法定義,如果一個運算式中混合了多個「運算子」,那麼該如何決定其優先順序呢?又或者 說,如何決定該呼叫哪個物件的哪個方法?例如 1 + 2 * 3,如何能決定為 (1).+((2).*(3)) ?而不是 ((1).+(2)).*(3) ? Scala 主要是由方法名稱的第一個字元來決定運算的順序,如果方法名稱的第一個字元是 *,則它比 + 有更高的優先順序,以下是方法第一個字元的優先順序 (由高而低),同一列表示優先順序相同 : 
除了以下字元外的其它特殊字元 
*、/、%
+、:
=、!
<、>
&

|
字母
指定運算(非=、<=、>=、==,且以=結尾方法)

所以運算符號一定優先於字母名稱的方法,例如 1 + 2 equals 3,結果就是 (1 + 2) equals 3。指定運算是 +=、-=、*= 、/= 等以 =結 尾,但又不是 =、<=、 >=、== 的運算方法,指定運算優先順序最低,所以 a *= 1 + 4,結果會是 a *= (1 + 4)。當然,最簡單的方式,還是使用括號來釐清優先順序. 當優先順序相同時,基本上由左至右進行運算,所以若 1 + 2 + 3 時,運算的順序是 (1 + 2) + 3,+ 號是左邊物件的方法,運算方法到底屬於哪個物件,這稱之為「關聯性」(Associativity)。一般情況下,運算方法都是屬於左邊物件,不過,當方法名稱是以 : 結尾時, 則該名稱會是右運算元的方法。在 Scala 中的例子是 List 的 ::,它用來在 List「前端」附加物件,例如 : 
scala> val x = List(1, 2)
x: List[Int] = List(1, 2)

scala> println(0::x)
List(0, 1, 2)

但 0 是個 Int,並沒有定義 :: 方法(就算是隱式轉換後的 RichInt 類別也沒有定義 :: 方法),這個操作是如何完成的?答案是 :: 是右邊物件的 方法,也就是 x 所參考的 ListList 物件上的方法,所以上面這個程式,等同於 : 
scala> println(x.::(0))
List(0, 1, 2)

這個程式顯示的結果也是 List(0, 1, 2)。如果你這麼寫,則程式會出錯 : 

由於 :: 以 : 結尾,所以 Scala 會認為要由右邊物件來呼叫 :: 方法,但 3 是個 Int,不會有 :: 方法,所以會出現「value :: is not a member of Int」的錯誤訊息. 由於 : 結尾的方法會被 Scala 視為右邊物件的方法,所以如果是 -1 :: 0 :: x,實際上的運算順序會是反過來從右至左,也就是 (-1 :: (0 :: x)). 由於在 Scala 中,任何的方法都可以撰寫運算子的形式,當你嘗試定義自己的「運算子」時,就必須注意操作的優先順序與關聯性 (也許像是 Array 的 /: 這樣的方法) . 

補充說明 :

沒有留言:

張貼留言

[Git 文章收集] Differences between git merge and git rebase

Source From  Here Preface Merging and rebasing are the two most popular way to applying changes from one branch into another one. They bot...