過時公告
現在,您已看到 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.toList
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
連結清單
連結清單是可變序列,由透過下一個指標連結的節點組成。它們由類別 LinkedList 支援。在大部分的語言中,null
會被選為空的連結清單。這不適用於 Scala 集合,因為即使是空的序列也必須支援所有序列方法。特別是 LinkedList.empty.isEmpty
應該傳回 true
,而不是拋出 NullPointerException
。空的連結清單會以特殊的方式編碼:它們的 next
欄位會指向節點本身。就像它們不可變的表親一樣,連結清單最適合順序遍歷。此外,連結清單可以輕鬆地將元素或連結清單插入另一個連結清單。
雙向連結清單
雙向連結清單類似於單向連結清單,只不過它們除了 next
之外,還有一個可變欄位 prev
,指向當前節點前面的元素。這個額外連結的主要好處是它可以讓元素移除變得非常快速。雙向連結清單由類別 DoubleLinkedList 支援。
可變清單
一個 MutableList 由一個單向鏈結串列和一個指向串列終端空節點的指標組成。這使得串列附加成為一個常數時間操作,因為它避免了必須遍歷串列來搜尋其終端節點。 MutableList 目前是 Scala 中 mutable.LinearSeq 的標準實作。
佇列
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)
陣列序列
陣列序列是固定大小的可變序列,它們在內部將其元素儲存在 Array[Object]
中。它們由 Scala 中的類別 ArraySeq 實作。
如果您想要一個具有效能特性的陣列,但您還想要建立序列的泛型實例,而您不知道元素的類型,而且您沒有 ClassTag
在執行階段提供它,您通常會使用 ArraySeq
。這些問題在 陣列 的區段中說明。
堆疊
您先前已經看過不可變堆疊。還有一個可變版本,由類別 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)
陣列堆疊
ArrayStack 是一種可變堆疊的替代實作,由一個依需要調整大小的陣列所支援。它提供快速的索引,而且通常比一般的可變堆疊在大部分操作上更有效率。
雜湊表
雜湊表將其元素儲存在底層陣列中,將每個項目放置在陣列中由該項目的雜湊碼所決定的位置。將元素新增到雜湊表中僅需常數時間,只要陣列中沒有其他元素具有相同的雜湊碼即可。因此,只要放置在雜湊表中的物件具有良好的雜湊碼分布,雜湊表就會非常快速。因此,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 作業外,它還提供下列原子作業
ConcurrentMap 類別中的作業
它是什麼 | 它執行什麼動作 |
---|---|
m putIfAbsent(k, v) |
新增鍵/值繫結 k -> v ,除非 k 已在 m 中定義 |
m remove (k, v) |
移除 k 的項目,如果它目前對應至 v 。 |
m replace (k, old, new) |
如果先前綁定至 old ,則將與金鑰 k 相關的值取代為 new 。 |
m replace (k, v) |
如果先前綁定至某個值,則將與金鑰 k 相關的值取代為 v 。 |
ConcurrentMap
是 Scala 集合函式庫中的特質。目前,其唯一實作是 Java 的 java.util.concurrent.ConcurrentMap
,可以使用 標準 Java/Scala 集合轉換 自動轉換為 Scala 地圖。
可變位元組
類型為 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)