Scala學習筆記02【陣列、列表、元組、集合和對映】
1、使用型別引數化陣列【Array】
Scala使用new例項化物件或類例項。
當在Scala裡實例化物件,可以使用值和型別把它引數化:parameterize。
引數化的意思是在你建立例項的時候”設定”它。
例如,例項化一個新的java.math.BigInteger並使用值”12345”引數化:
val big = new java.math.BigInteger("12345")
一個完整例項:
object HelloWorld
{
def main(args: Array[String])
{
val greetStrings = new Array[String](3)
greetStrings(0) = "Scala: Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
for (i <- 0 to 2)
print(greetStrings(i))
}
}
//輸出結果:Scala: Hello, world!
Scala裡的陣列是通過把索引放在圓括號裡面訪問的,而不是像Java那樣放在方括號裡。所以陣列的第零個元素是greetStrings(0),不是greetStrings[0]。
這幾行程式碼演示了搞明白Scala如何看待val的意義的重要概念。當你用val定義一個變數,那麼這個變數就不能重新賦值,但它指向的物件卻仍可以改變。
在本例中,你不能把greetStrings重新賦值成不同的陣列;greetStrings將永遠指向那個它被初始化時候指向的同一個Array[String]例項。
但是你能一遍遍修改那個Array[String]的元素,因此陣列本身是可變的。
表示式:
for (i <- 0 to 2)
print(greetStrings(i))
這個for表示式的第一行程式碼演示了Scala的另一個通用規則:
如果方法僅帶一個引數,你可以不帶點或括號的呼叫它。
to實際上是帶一個Int引數的方法:程式碼0 to 2被轉換成方法呼叫(0).to(2)。
Scala沒有操作符過載,在Scala直譯器裡輸入1 + 2,你實際上正在Int物件1上呼叫一個名為+的方法,並把2當作引數傳給它。
也可以使用傳統的方法呼叫語法把1 + 2替代寫成(1).+(2)。
//Scala通常可以更簡潔的方法創造和初始化:
val numNames = Array("zero", "one", "two")
//實際上更羅嗦的呼叫同樣的apply方法的辦法是:
val numNames2 = Array.apply("zero", "one", "two")
2、使用列表【List】
Scala陣列是一個所有物件都共享相同型別的可變序列。比方說Array[String]僅包含String。儘管例項化之後你無法改變Array的長度,它的元素值卻是可變的。因此,Array是可變的物件。
Scala的List類是共享相同型別的不可變物件序列。
和陣列一樣,List[String]包含的僅僅是String。
Scala的List不同於Java的java.util.List,總是不可變的(而Java的List可變)。
//建立一個Scala的List很簡單
val oneTwoThree = List(1, 2, 3)
上述程式碼完成了一個新的叫做oneTwoThree的val,並已經用帶有整數元素值1,2和3的新List[Int]初始化。
這個List可以這麼用:
val oneTwo = List(1, 2)
val threeFour = List(3, 4)
val oneTwoThreeFour = oneTwo ::: threeFour
println(oneTwo + " 和 " + threeFour + " 是不可變的")
println("看, " + oneTwoThreeFour + "是個新列表了")
//執行結果:
List(1, 2) 和 List(3, 4) 是不可變的
看, List(1, 2, 3, 4)是個新列表了
List最常用的操作符是發音為”cons”的” :: “. 例如,
val twoThree = list(2, 3)
val oneTwoThree = 1 :: twoThree
println(oneTwoThree)
//結果為:List(1, 2, 3)
類List沒有提供append操作。
如果你想通過新增元素來構造列表:
I、字首進去,完成之後再呼叫reverse;
II、使用ListBuffer,一種提供append操作的可變列表,完成之後呼叫toList。
3、使用元組【Tuple】
另一種有用的容器物件是元組:tuple。與列表一樣,元組也是不可變的,但與列表不同,元組可以包含不同型別的元素。
列表應該是List[Int]或List[String]的樣子,元組可以同時擁有Int和String。
Scala裡你可以簡單地返回一個元組。
而且這麼做的確簡單:例項化一個裝有一些物件的新元組,只要把這些物件放在括號裡,並用逗號分隔即可。
一旦你已經例項化了一個元組,你可以用點號,下劃線和一個基於1的元素索引訪問它。
一個例子:
val pair = (99, "Luftballons") //Scala推斷元組型別為Tuple2[Int, String],並把它賦給變數pair。
println(pair._1) //訪問_1欄位,從而輸出第一個元素,99。
println(pair._2)
//執行結果
99
Luftballons
元組第一個元素是以99為值的Int,第二個是”luftballons”為值的String。
元組的實際型別取決於它含有的元素數量和這些元素的型別。
因此,(99, “Luftballons”)的型別是Tuple2[Int, String]。
類似地,(‘u’, ‘r’, ‘the’, 1, 4, “me”)是Tuple6[Char, Char, String, Int, Int, String]。
訪問元組的元素
為什麼你不能像訪問List裡的元素那樣訪問元組的,就像pair(0)?
因為List的apply方法始終返回同樣的型別,但是元組裡的或許型別不同。
_1可以有一個結果型別,_2是另外一個。
另:元組元素編號從1開始。
4、使用Set和Map
當問題討論到集和對映,Scala同樣提供了可變和不可變的替代品,不過用了不同的辦法。
對於集和對映,Scala把可變性建模在類繼承中。
例如,Scala的API包含了集的一個基本特質:trait,特質這個概念接近於Java的介面。
Scala於是提供了兩個子特質,一個是可變的集,另一個是不可變的集。這三個特質都共享同樣的簡化名,Set。
如果你想要使用HashSet,你可以根據你的需要選擇可變的或不可變的變體。
創造集的預設方法例項:
var jetSet = Set("Boeing", "Airbus") //定義了名為jetSet的新var,包含兩個字串
jetSet += "Lear" // jetSet = jetSet + "Lear"
println(jetSet.contains("Cessna")) //列印輸出集是否包含字串"Cessna"。
println(jetSet.contains("Lear")) //列印輸出集是否包含字串"Lear"。
//執行結果:
false
true
需要不可變集,就需要使用一個引用:import,如下所示:
import scala.collection.mutable.Set
val movieSet = Set("Hitch", "Poltergeist")
movieSet += "Shrek"
println(movieSet)
//執行結果:
Set(Poltergeist, Shrek, Hitch)
需要一個不可變的HashSet,你可以這麼做:
import scala.collection.immutable.HashSet
val hashSet = HashSet("Tomatoes", "Chilies")
println(hashSet + "Coriander")
//執行結果
Set(Chilies, Tomatoes, Coriander)
Map是Scala裡另一種有用的集合類。
和集一樣,Scala採用了類繼承機制提供了可變的和不可變的兩種版本的Map。
scala.collection包裡面有一個基礎Map特質和兩個子特質Map:
可變的Map在scala.collection.mutable裡,不可變的在scala.collection.immutable裡。
可變對映的創造過程:
import scala.collection.mutable.Map
val treasureMap = Map[Int, String]()
treasureMap += (1 -> "我在")
treasureMap += (2 -> "學習")
treasureMap += (3 -> "Scala")
println(treasureMap(1) + treasureMap(2) + treasureMap(3))
//執行結果:
我在學習Scala.
至於不可變對映,就不用引用任何類了,因為不可變對映是預設的,程式碼例子:
val romanNumeral = Map(
1 -> "我", 2 -> "是", 3 -> "缺", 4 -> "省", 5 -> "的" )
println(romanNumeral(1) + romanNumeral(2) + romanNumeral(3) + romanNumeral(4) + romanNumeral(5))
//執行結果:
我是預設的