Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

配列をfreezeする時は、ちゃんと中身もfreezeしとく

配列をfreezeする場合は

  • mapにfreezeメソッドを渡し中身を定数化
  • 配列自体をfreezeし、本体も定数化

という手順を取ります。

ためしに、最初の手順だけで止めると

str_frozen = %w(foo bar buzz).map(&:freeze)                                                                                     
#=> ["foo", "bar", "buzz"]

str_frozen[0].frozen?
#=> true

str_frozen.frozen?
#=> false

と、配列そのものは定数化していない事が確認できます。
というわけで、ちゃんと配列本体にもfreezeをかけてあげます。

ary_frozen = %w(foo bar buzz).map(&:freeze).freeze                                                                              
#=> ["foo", "bar", "buzz"]

ary_frozen.frozen?                                                                                                           
#=> true

以降は定数化されてるので、これに変更を加えようとすると

ary_frozen << "test"
# 2> RuntimeError: can't modify frozen Array

となりエラーを吐き出します。

じゃあ、本体だけfreezeするとどうなるんです?

記事を書き終わったあとに気になったので試してみました。
結果は……使えない事はないものの、要素が凍結されてるか参照するとエラーを吐きます。

buff = %w(a b c).freeze
#=> ["a", "b", "c"]

buff.frozen?
#=> true

buff[0]
#=> "a"

buff[0] = 'b'
# 2> RuntimeError: can't modify frozen Array

buff[0].forzen?
# 2>NoMethodError: undefined method `forzen?' for "a":String

参考もと

Effective Ruby

Effective Ruby