資料結構是一個很棒的發明, 豐富了原本看起來只是0和1的電腦世界, 很多現實世界中的事物才可以藉此數位化的保存與傳遞, 複雜的資料結構都是由簡單的元件組合而成的, 在Scala之前最常見的簡單結構是Array, Array讓資料得以方便複數處理, 在Scala後更開始依賴List的活性, 在Scala中不是創造了新的架構, 而是在原本熟悉的架構中, 提供更有j完善的操作函式, 讓軟體更加容易更快去面對複雜的世界
Array in Scala
在Scala basic1有提到Scala的變數第一特性就是val or var(可變動or不可變動), 而變數的複數集結構也因此有了可變動or不可變動的差別, 所以在Scala中Array代表的是一系列Mutable variable, 反之List 就是一串列Immutable variableval array = new Array[String](3) Array[String] = Array(null, null, null) array(0) = "Array" array(1) = "is" array(2) = "mutable" //array = Array[String] = Array(This, is, mutable)這邊你要注意的是中括號 [ ] 的用法, 中括號 [ ] 主要是用來表示類型語意&參數化語意, 因此相較於JAVA or C的中括號 [ ] 是用來表示Array的索引位置, Scala中, 中括號 [ ]是用來表示要創造甚麼類型的Array, 上例中Array[String] 就是創造String 的Array, 再者改用小括號 ( ) 來當作Array的索引位置, 因此array(0) 就是Array中第一個元素為 "Array"
在Scala中為了善用Functional programming的概念, 針對很多基本結構有加了很多有用的Method, 讓你可以透過Function組合來開發程式
array.foreach(println)foreach method就像你創一個for迴圈, 在迴圈中針對Array中每一個元素做同一個運算, 運算的內容就是對你傳入foreach的參數:Function運算, 在上例是把一個 println 函式當作Function literal(函式本體)傳入foreach的參數中, 接著foreach會把array中每一個元素都傳到 println 裡面,最後就會印出整個array
更完整的Array功能可以參照 Scaladoc for scala.collection.mutable.ArrayLike. 你會發現ArrayLike跟你在用的Array是不同的class, 憑甚麼要去參照ArrayLike而非Array? 這是因為Predef object的關係, 透過Predef object去幫你做隱式轉換, 會把Array轉換成 scala.collection.mutable
.ArrayOps. ArrayOps 又繼承自 ArrayLike, 也因此透過ArrayLike才可以看見Array的全貌
Predef
Scala compiler會自動幫你 import 一些基本會用到的class, 比如 java.lang, Scala package, 以及scala.Predef object, Predef針對Scala標準Library 有做類型別稱, 會幫你自動做名稱轉換, 比如 println function是 scala.Console的, 是使用System.out.println, 因此當你直接使用println, Predef會幫你自動轉換成scala.Console.println
List in Scala
Array是Mutable的資料結構, 意味著你會變動到陣列中變數的值進而造成Side effect, 為了平行處理上有著安全的資料共享方式, 應該是拿原本變數的值去運算出新的值, 新的值是在存新的變數,藉此也不會改到原本的變數, 這樣就得用Immutable的 List, 其實List是來自於 scala.collection.immutable.List, 不過透過Predef的轉換你可以直接使用不需要去打這一大串val myList = List(1,2,3) // myList[Int] = List(1,2,3) myList.getClass // print java.lang.Class[_] = class scala.collection.immutable.$colon$colon
你會好奇 myList 明明是 List class, 怎麼call getClass 會得到scala.collection.immutable.$colon$colon, 事實上 scala.collection.immutable.List是一個抽象畫類別, 它是由另外兩個class實作出來, 一個是 scala.Nil 另一個是 scala.::. , ( :: (兩個冒號) 是一個合法的class名稱, 可以用它去命名class) 其中Nil class代表的是一個空的List, :: class代表的是非空的List(List有 1~n 個元素)
List 是一個Immutable List, 也因此當你增加or刪減List中的元素, 會產生一個修改後的新 List
val List1 = List(1, 2) //List1: List[Int] = List(1, 2) val List2 = 3 :: List1 //List2: List[Int] = List(3, 1, 2) List1 //List[Int] = List(1, 2) List1還是沒變在上例中, 透過 :: 為一個List去增加新的元素, 這邊得先注意一下 :: method是右邊 List1物件的Method, :: 以兩個冒號為名稱的method它是屬於右邊物件的Method
:: method 會拿它本身所屬的List物件的所有元素為基底, 上例是拿 List1 的 1, 2元素, 然後結合 :: 左邊的要加入的元素, 以新加入的元素為第一個, 形成一個新的 List, 如果你要把新元素加在元本List 的尾巴, 你得用 :+ method
val List3 = List1 :+ 3 // List3 = List[Int] = List(1, 2, 3)更特殊的建造List方法
val myList = "This" :: "is" :: "immutable" :: Nil myList: List[java.lang.String] = List(This, is, immutable)Nil 本身就是一個空的List, 用Nil 的 :: method加上 immutable字串後產生新的List, 再用新的List :: method再加上 is 字串再產生新的List如此迭代下去最後形成List(This , is , immutable)
當你要刪除List 中某一元素, 你可以用 - method, 不過這個method已被棄用(deprecated), 未來版本不再維護, 官方也不保證其正確性了. 最好的方式是用FileterNot method
val afterDelete = List3.filterNot(_ == 3) //afterDelete: List[Int] = List(1, 2)FileterNot method接受一個判斷敘述式, 過濾掉List中符合該判斷敘述式的元素, 並把剩下的元素合成一個新的List 回傳出來
對於List已經有基本的認知和了解, 往後會再深入Collection相關的應用會有更仔細的解說, 現在開始也可以好好的試用List 來coding了
繼續閱讀 Scala basic4, For-comprehensions
沒有留言:
張貼留言