您現在已經看過 Scala 在其標準程式庫中提供的最常使用的不可變集合類別。現在來看看可變集合類別。
陣列緩衝區
一個 ArrayBuffer 緩衝區包含一個陣列和一個大小。對陣列緩衝區執行的大部分操作速度與陣列相同,因為這些操作僅存取和修改底層陣列。此外,可以有效率地將資料新增到陣列緩衝區的結尾。將一個項目附加到陣列緩衝區需要攤銷常數時間。因此,當新項目總是新增到結尾時,陣列緩衝區對於有效率地建立大型集合很有用。
scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int]
buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> buf += 1
res32: buf.type = ArrayBuffer(1)
scala> buf += 10
res33: buf.type = ArrayBuffer(1, 10)
scala> buf.toArray
res34: Array[Int] = Array(1, 10)
串列緩衝區
一個 ListBuffer 類似於陣列緩衝區,只不過它在內部使用連結串列,而不是陣列。如果您計畫在建立串列緩衝區後將其轉換為串列,請使用串列緩衝區,而不是陣列緩衝區。
scala> val buf = scala.collection.mutable.ListBuffer.empty[Int]
buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
scala> buf += 1
res35: buf.type = ListBuffer(1)
scala> buf += 10
res36: buf.type = ListBuffer(1, 10)
scala> buf.to(List)
res37: List[Int] = List(1, 10)
字串產生器
就像陣列緩衝區對於建立陣列很有用,串列緩衝區對於建立串列很有用,StringBuilder 對於建立字串很有用。字串產生器非常常用,它們已經匯入預設名稱空間中。使用簡單的 new StringBuilder
建立它們,如下所示
scala> val buf = new StringBuilder
buf: StringBuilder =
scala> buf += 'a'
res38: buf.type = a
scala> buf ++= "bcdef"
res39: buf.type = abcdef
scala> buf.toString
res41: String = abcdef
scala> val buf = StringBuilder()
buf: StringBuilder =
scala> buf += 'a'
res38: buf.type = a
scala> buf ++= "bcdef"
res39: buf.type = abcdef
scala> buf.toString
res41: String = abcdef
陣列雙端佇列
一個 ArrayDeque 是一個序列,支援在前端和結尾有效率地新增元素。它在內部使用一個可調整大小的陣列。
如果您需要將元素附加和預先附加到緩衝區,請使用 ArrayDeque
,而不是 ArrayBuffer
。
佇列
Scala 除了提供不可變佇列之外,還提供可變佇列。您可以使用 mQueue
的方式類似於使用不可變佇列的方式,但您使用 +=
和 ++=
營運子來附加,而不是使用 enqueue
。此外,在可變佇列上,dequeue
方法只會從佇列中移除頭元素並傳回它。以下是一個範例
scala> val queue = new scala.collection.mutable.Queue[String]
queue: scala.collection.mutable.Queue[String] = Queue()
scala> queue += "a"
res10: queue.type = Queue(a)
scala> queue ++= List("b", "c")
res11: queue.type = Queue(a, b, c)
scala> queue
res12: scala.collection.mutable.Queue[String] = Queue(a, b, c)
scala> queue.dequeue
res13: String = a
scala> queue
res14: scala.collection.mutable.Queue[String] = Queue(b, c)
scala> val queue = scala.collection.mutable.Queue[String]()
queue: scala.collection.mutable.Queue[String] = Queue()
scala> queue += "a"
res10: queue.type = Queue(a)
scala> queue ++= List("b", "c")
res11: queue.type = Queue(a, b, c)
scala> queue
res12: scala.collection.mutable.Queue[String] = Queue(a, b, c)
scala> queue.dequeue
res13: String = a
scala> queue
res14: scala.collection.mutable.Queue[String] = Queue(b, c)
堆疊
堆疊實作一種資料結構,允許以後進先出 (LIFO) 的方式儲存和擷取物件。它由類別 mutable.Stack 提供支援。
scala> val stack = new scala.collection.mutable.Stack[Int]
stack: scala.collection.mutable.Stack[Int] = Stack()
scala> stack.push(1)
res0: stack.type = Stack(1)
scala> stack
res1: scala.collection.mutable.Stack[Int] = Stack(1)
scala> stack.push(2)
res0: stack.type = Stack(1, 2)
scala> stack
res3: scala.collection.mutable.Stack[Int] = Stack(1, 2)
scala> stack.top
res8: Int = 2
scala> stack
res9: scala.collection.mutable.Stack[Int] = Stack(1, 2)
scala> stack.pop
res10: Int = 2
scala> stack
res11: scala.collection.mutable.Stack[Int] = Stack(1)
scala> val stack = scala.collection.mutable.Stack[Int]()
stack: scala.collection.mutable.Stack[Int] = Stack()
scala> stack.push(1)
res0: stack.type = Stack(1)
scala> stack
res1: scala.collection.mutable.Stack[Int] = Stack(1)
scala> stack.push(2)
res0: stack.type = Stack(1, 2)
scala> stack
res3: scala.collection.mutable.Stack[Int] = Stack(1, 2)
scala> stack.top
res8: Int = 2
scala> stack
res9: scala.collection.mutable.Stack[Int] = Stack(1, 2)
scala> stack.pop
res10: Int = 2
scala> stack
res11: scala.collection.mutable.Stack[Int] = Stack(1)
可變動 ArraySeq
陣列序列是大小固定的可變動序列,它們在內部以 Array[Object]
儲存其元素。它們在 Scala 中由類別 ArraySeq 實作。
如果你想要一個效能特徵良好的陣列,但你又想要建立序列的泛型實例,而你不知道元素的類型,而且你沒有 ClassTag
在執行階段提供它,你通常會使用 ArraySeq
。這些問題在 陣列 的章節中說明。
雜湊表
雜湊表將其元素儲存在底層陣列中,將每個項目放置在由該項目的雜湊碼決定的陣列位置。將元素新增到雜湊表只需要常數時間,只要陣列中沒有另一個元素具有相同的雜湊碼。因此,只要放置在雜湊表中的物件具有良好的雜湊碼分佈,雜湊表就會非常快速。因此,Scala 中的預設可變動映射和設定類型是基於雜湊表的。你也可以直接使用名稱 mutable.HashSet 和 mutable.HashMap 來存取它們。
雜湊設定和映射的使用方式與任何其他設定或映射相同。以下是一些簡單的範例
scala> val map = scala.collection.mutable.HashMap.empty[Int,String]
map: scala.collection.mutable.HashMap[Int,String] = Map()
scala> map += (1 -> "make a web site")
res42: map.type = Map(1 -> make a web site)
scala> map += (3 -> "profit!")
res43: map.type = Map(1 -> make a web site, 3 -> profit!)
scala> map(1)
res44: String = make a web site
scala> map contains 2
res46: Boolean = false
迭代雜湊表並未保證會以任何特定順序執行。迭代只會以雜湊表底層陣列的順序進行。若要取得保證的迭代順序,請使用連結雜湊映射或集合,而不是一般雜湊映射或集合。連結雜湊映射或集合就像一般的雜湊映射或集合,但它還包含一個元素的連結清單,順序則為元素新增的順序。此類集合的迭代順序永遠與元素最初新增的順序相同。
弱雜湊映射
弱雜湊映射是一種特殊的雜湊映射,其中垃圾回收器不會追蹤從映射到儲存在其中的金鑰的連結。這表示如果沒有其他金鑰參考,金鑰及其關聯的值將會從映射中消失。弱雜湊映射適用於快取等任務,其中您想要在函式再次針對相同金鑰呼叫時重複使用昂貴函式的結果。如果金鑰和函式結果儲存在一般的雜湊映射中,映射可能會無限擴充,而且永遠不會有任何金鑰變成垃圾。使用弱雜湊映射可以避免這個問題。金鑰物件一變得無法到達,其項目就會從弱雜湊映射中移除。Scala 中的弱雜湊映射由類別 WeakHashMap 實作,作為底層 Java 實作 java.util.WeakHashMap
的包裝器。
並發映射
並發映射可以同時由多個執行緒存取。除了常見的 Map 作業之外,它還提供下列原子作業
concurrent.Map 類別中的作業
功能 | 執行動作 |
---|---|
m.putIfAbsent(k, v) |
加入鍵值繫結 k -> v ,除非 k 已在 m 中定義 |
m.remove(k, v) |
如果目前 k 對應到 v ,則移除該項目。 |
m.replace(k, old, new) |
如果 k 鍵值先前繫結到 old ,則將其繫結到 new 。 |
m.replace (k, v) |
如果 k 鍵值先前繫結到某個值,則將其繫結到 v 。 |
concurrent.Map
是 Scala 集合函式庫中的特質。目前,它有兩個實作。第一個是 Java 的 java.util.concurrent.ConcurrentMap
,可以使用 標準 Java/Scala 集合轉換 自動轉換為 Scala 地圖。第二個實作是 TrieMap,它是雜湊陣列對應樹的無鎖實作。
可變動位元組
mutable.BitSet 類型的可變動位元組集合就像不可變動位元組集合一樣,只不過它是就地修改。可變動位元組集合在更新時比不可變動位元組集合稍微有效率,因為它們不必複製未變更的 Long
。
scala> val bits = scala.collection.mutable.BitSet.empty
bits: scala.collection.mutable.BitSet = BitSet()
scala> bits += 1
res49: bits.type = BitSet(1)
scala> bits += 3
res50: bits.type = BitSet(1, 3)
scala> bits
res51: scala.collection.mutable.BitSet = BitSet(1, 3)