可變(mutable)集合與不可變(immutable)集合
為了更易於完成不可變集合到可變集合的轉換,或者反向轉換,Scala提供了一些語法糖。縱使不可變集和映射並不支持真正的+=方法,Scala還是為此提供了+=的語法解釋。
scala> val people = Set("Nancy", "Jane")
people: scala.collection.immutable.Set[String] = Set(Nancy, Jane)
scala> people += "Bob"
<console>:9: error: value += is not a member of scala.collection.immutable.Set[S
tring]
people += "Bob"
^
然而如果people聲明為var,而不是val,那么集合就可以用+=操作完成“更新”,盡管它是不可變類型的。首先,新創建集合;然后,people將被重新賦值為新集合:
scala> var people = Set("Nancy", "Jane")
people: scala.collection.immutable.Set[String] = Set(Nancy, Jane)
scala> people += "Bob"
scala> people
res2: scala.collection.immutable.Set[String] = Set(Nancy, Jane, Bob)
同樣的理念可以應用於所有以=結尾的方法,而不僅是+=方法。以下代碼把該語法應用於-=操作符,從集中移除元素;以及++=操作符,把集合的所有元素添加到集里面:
scala> people -= "Jane" scala> people ++= List("Tom", "Harry") scala> people res5: scala.collection.immutable.Set[String] = Set(Nancy, Bob, Tom, Harry)
這塊語法糖不僅對集合有效,它還具有普適性。例如,下面是用在浮點數上的:
scala> var roughlyPi = 3.0 roughlyPi: Double = 3.0 scala> roughlyPi += 0.1 scala> roughlyPi += 0.04 scala> roughlyPi res8: Double = 3.14
這種擴展的效果類似於Java的賦值操作符+=、-=、*=等,不過其更為通用,因為所有以=結尾的操作符都可以做轉化。
初始化集合
最常見的創建和初始化集合的方法是把初始值傳遞給要用的集合類型的伴生對象的工廠方法。你只須把元素放在伴生對象名后面的括號中,Scala編譯器就會把它轉化為該伴生對象的apply方法調用:
scala> List(1, 2, 3) res9: List[Int] = List(1, 2, 3) scala> Set('a', 'b', 'c') res10: scala.collection.immutable.Set[Char] = Set(a, b, c) scala> import scala.collection.mutable import scala.collection.mutable scala> mutable.Map("hi" -> 2, "there" -> 5) res11: scala.collection.mutable.Map[String,Int] = Map(hi -> 2, there -> 5) scala> Array(1.0, 2.0, 3.0) res12: Array[Double] = Array(1.0, 2.0, 3.0)
盡管通常都可以讓Scala的編譯器從傳遞給工廠方法的元素推斷集合的元素類型,但有些時候或許你會希望指定以不同於編譯器所選的類型創建集合。尤其對於可變集合來說更是如此。舉例如下:
scala> import scala.collection.mutable import scala.collection.mutable scala> val stuff = mutable.Set(42) stuff: scala.collection.mutable.Set[Int] = Set(42) scala> stuff += "abracadabra" <console>:11: error: type mismatch; found : String("abracadabra") required: Int stuff += "abracadabra" ^
這里的問題在於stuff被指定的類型為Int。如果想要讓它的類型為Any,你需要明確地說明,把元素類型放在方括號里,如下:
scala> val stuff = mutable.Set[Any](42)
stuff: scala.collection.mutable.Set[Any] = Set(42) scala> stuff += "abracadabra" res14: stuff.type = Set(abracadabra, 42)
另一種特殊情況是,你想要把集合初始化為指定類型。例如,設想你要把列表中的元素保存在TreeSet中。列表如下:
scala> val colors = List("blue", "yellow", "red", "green")
colors: List[String] = List(blue, yellow, red, green)
你不能把colors列表傳遞給TreeSet工廠方法:
scala> import scala.collection.immutable.TreeSet import scala.collection.immutable.TreeSet scala> val treeSet = TreeSet(colors) <console>:11: error: No implicit Ordering defined for List[String]. val treeSet = TreeSet(colors) ^
實際上,需要創建空的TreeSet[String]對象並使用TreeSet的++操作符把列表元素加入其中:
scala> val treeSet = TreeSet[String]() ++ colors
treeSet: scala.collection.immutable.TreeSet[String] = TreeSet(blue, green, red,yellow)
數組與列表之間的互轉
另一方面,如果你需要用集合初始化列表或數組,非常簡單,直接做就是了。使用集合初始化列表,只須對集合調用toList方法:
scala> treeSet.toList
res0: List[String] = List(blue, green, red, yellow)
或者,如果需要的是數組,則調用toArray:
scala> treeSet.toArray
res1: Array[String] = Array(blue, green, red, yellow)
請牢記,轉變為列表或數組同樣需要復制集合的所有元素,因此對於大型集合來說可能比較慢。
集合映射的可變與不可變互轉
另一種偶爾發生的情況是把可變集或映射轉換成不可變類型,或者反向轉換。要做到這一點,你可以利用前面以列表元素初始化TreeSet時的演示技巧。比如說你想要把當前使用的可變集合轉換成不可變集合,可以先創建空的不可變集合,然后把可變集合的元素用++操作符添加進去。下面的代碼說明了如何把前面例子里的不可變TreeSet轉換為可變集,再轉回不可變集:
scala> import scala.collection.mutable import scala.collection.mutable scala> treeSet res2: scala.collection.immutable.TreeSet[String] = TreeSet(blue, green, red, yel low) scala> val mutaSet = mutable.Set.empty ++ treeSet mutaSet: scala.collection.mutable.Set[String] = Set(red, blue, green, yellow) scala> val immutaSet = Set.empty ++ mutaSet immutaSet: scala.collection.immutable.Set[String] = Set(red, blue, green, yellow )
可以使用同樣的技巧實現可變映射與不可變映射之間的轉換:
scala> val muta = mutable.Map("i" -> 1, "ii" -> 2)
muta: scala.collection.mutable.Map[String,Int] = Map(ii -> 2, i -> 1)
scala> val immu = Map.empty ++ muta
immu: scala.collection.immutable.Map[String,Int] = Map(ii -> 2, i -> 1)
