Some mind blown examples:
```rb
[1] pry(main)> list = Array.new(5, "foo")
# => ["foo", "foo", "foo", "foo", "foo"]
[2] pry(main)> list[4].clear
# => ""
[3] pry(main)> list
# => ["", "", "", "", ""]
```
因為每個 default foo 都是同一個 object
以及
```rb
[1] pry(main)> master_list = Hash.new([])
# => {}
[2] pry(main)> master_list[:evens] << 2
# => [2]
[3] pry(main)> master_list[:odds] << 3
# => [2, 3]
[4] pry(main)> master_list
# => {}
[5] pry(main)> master_list[:evens] <<= 4
# => [2, 3, 4]
[6] pry(main)> master_list
# => {:evens=>[2, 3, 4]}
[7] pry(main)> master_list[:odds] <<= 5
# => [2, 3, 4, 5]
[8] pry(main)> master_list
# => {:evens=>[2, 3, 4, 5], :odds=>[2, 3, 4, 5]}
```
一樣的原理,每個 default array 都是同一個 object
一個避免這樣的做法是用 proc 確保每個 default 值是不同 object,例如:
```rb
Array.new(5) { "foo" }
Hash.new { [] }
```
ex:
```rb
[1] pry(main)> Array.new(5) { "foo" }
=> ["foo", "foo", "foo", "foo", "foo"]
[2] pry(main)> a = Array.new(5) { "foo" }
=> ["foo", "foo", "foo", "foo", "foo"]
[3] pry(main)> a[2].clear
=> ""
[4] pry(main)> a
=> ["foo", "foo", "", "foo", "foo"]
[5] pry(main)>
```
另外還有更有趣的「以你為 freeze 了是吧?Boom~!」
```rb
[1] pry(main)> CONSTANT = ["foo"]
# => ["foo"]
[2] pry(main)> CONSTANT << "bar"
# => ["foo", "bar"]
[3] pry(main)> CONSTANT.freeze
# => ["foo", "bar"]
[4] pry(main)> CONSTANT << "baz"
# RuntimeError: can't modify frozen Array
# from (pry):4:in `__pry__'
[5] pry(main)> CONSTANT[1] << "baz"
# => "barbaz"
[6] pry(main)> CONSTANT
# => ["foo", "barbaz"]
```
這是因為 freeze 是 freeze CONSTANT 這個 Array 的 object,沒有 freeze 裡面的 string,所以 string 還是 mutable
(Ice Nine gem for deep freezing)
為了拯救 developers 於水深火熱的加班 debug 地獄中,不需要 mutate 的時候就不要 mutate,寫每個 function 都想一下「這真的有必要 mutate 嗎?」
沒有留言:
張貼留言