在寫scala的時候,常常不太明白Mutable and Immutable Collections的用法和差別。官方文檔說得很清楚:
A mutablecollection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by contrast, never change.
但是我們在用的時候很發現這兩個并沒什麼異樣。
一、擺例子,抛出疑惑
例子1-1:
object Test1 extends App() {
var map = new scala.collection.mutable.HashMap[Int, String];
map += (1 -> "1");
map += (2 -> "2");
map += (3 -> "3")
map += (4 -> "4");
map += (1 -> "5");
println(map.mkString("\n"));
}
結果:
1 -> 5
2 -> 2
3 -> 3
4 -> 4
這裡可以看出是沒什麼問題的,但是如果把第一行改為immutable的HashMap,你會發現結果依舊沒有變。(可能順序有點變化)
例子1-2:
var map = new scala.collection.immutable.HashMap[Int, String];
結果:
1 -> 5
2 -> 2
3 -> 3
4 -> 4
那麼就奇怪了,其實對于這個基礎好的碼農一眼就知道了原因,所有的的存在某種問題或陰謀都在+=這個操作符上,每次+=操作之後都會傳回一個新的對象
也就是說這裡共産生了6個map新對象。是以最後輸出map的時候其實是最新的那個對象,原來的對象并沒有變化。
那麼問題是否這樣呢?
二、深入驗證假設。
例子2-1:
object Test1 extends App() {
var map = new scala.collection.mutable.HashMap[Int, String];
map += (1 -> "1");
map += (2 -> "2");
var tem = map;
tem += (1 -> "5");
println(map.mkString(" || "));
println("---------------")
println(tem.mkString(" || "));
}
結果:
2 -> 2 || 1 -> 5
---------------
2 -> 2 || 1 -> 5
奇怪的現象又來了,不是說好的+=操作每次都會傳回新對象嗎?這個試驗的結果很明顯最後的tem對象 += 的改變仍然會引起map對象的改變。
也就是說
tem += (1 -> "5");
根本不會引起一個新對象的産生。它們都指向同一個記憶體空間。fuck,我要砸鍵盤了!!!!
别急,請看第二個例子
例子2-2:
修改第一行為:
var map = new scala.collection.immutable.HashMap[Int, String];
結果:
1 -> 1 || 2 -> 2
---------------
1 -> 5 || 2 -> 2
好了,這個倒是符合我們當初的假設,暫時不砸鍵盤。
三、總結:
相信聰明的人一下子就能看出差別了。scala用心良苦,在+=這個操作符上為我們花了不少功夫。
+=這個操作符,如果操作的對象是可變的,它會自動調用對象的update方法(具體對象看具體操作),相當于更新或者追加的操作。
如果對象是不可變的,它就會傳回一個新的對象。
問題擴充:為什麼要花費精力弄明白可變與不可變對象的差別?(這個涉及到多線程安全,循環周遊等,具體自己上網查)