Array.new(3,'a')Array.new(3){'b'} は全く異なる動きをします。

同じ文字列オブジェクトへの参照の配列を作りたい場合は別として、通常は、同じ文字の配列を作る場合は、 Array.new(3){'b'} を取るべきです。


Array.new(3,'a') の場合

a = Array.new(3,'a')  # => ['a','a','a']
a[0].upcase!          # 配列の最初を大文字に
p a                   # => ['A','A','A']

なんと、すべて大文字になってしまいました。3つの値は、すべて同じ文字列オブジェクトへの参照になっているからです。


数字の場合は、どうでしょうか?

a = Array.new(3,3)  # => [3,3,3]
a[0] += 1           # 配列の最初に1を足す
p a                 # => [4,3,3]

直のオブジェクトなので問題ありません。


最初の文字列と同様の現象は、配列にしてみるとオブジェクトへの参照になり、同じような現象になります。浅いコピーの現象と同じです。

a = Array.new(3,[3])  # => [[3], [3], [3]]
a[0] << 1             # 配列の最初に要素を加える
p a                   # => [[3, 1], [3, 1], [3, 1]]



Array.new(3){'b'} の場合

a = Array.new(3){'b'} # => ['b','b','b']
a[0].upcase!          # 配列の最初を大文字に
p a                   # => ['B','b','b']

この場合は、文字列の参照ではなく、文字列オブジェクトそのものになるため要素は独立しています。


文字列にしてみても配列にしても独立してますね。

a = Array.new(3){'bb'}  # => ["bb", "bb", "bb"]
a[0].upcase!            # 配列の最初を大文字に
p a                     # => ["BB", "bb", "bb"]

a = Array.new(3){[5]}  # => [[5], [5], [5]]
a[0] << 1               # 配列の最初に要素を加える
p a                     # [[5, 1], [5], [5]]


fillnew と同じ考え

a = []
a.fill('a',2..4)  # => [nil, nil, "a", "a", "a"]
a[3].upcase!      # 配列の4番めを大文字に
p a               # => [nil, nil, "A", "A", "A"]

a.fill(2..4){'b'} # => [nil, nil, "b", "b", "b"]
a[3].upcase!      # 配列の4番めを大文字に
p a               # => [nil, nil, "b", "B", "b"]


直接入力すれば、別物として値は変わります。

a.fill('a', 2..5) # => [nil, nil, "a", "a", "a", "a"]
a[3].upcase!      # 配列の4番めを大文字に
p a               # => [nil, nil, "A", "A", "A", "A"]
a[2] = 'c'        # 配列の3番目に直接代入
p a               # => [nil, nil, "c", "A", "A", "A"]
2024/08/09