22
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby 3.0に備え、文字列の凍結/解凍方法を確認する

Last updated at Posted at 2015-12-18

Ruby 3.0 から文字列リテラルがデフォルトで immutable (frozen) になるかもしれないと知り、気になったので、文字列の凍結/解凍について確認してみた。

文字列の凍結

Ruby では、Object#freeze でオブジェクトを凍結(内容の変更を禁止)できる。

String は Object を継承しているので、String#freeze で凍結できる。

s = 'hoge'
s.frozen?    # => false
s.freeze
s.frozen?    # => true
s << 'fuga'  # => RuntimeError: can't modify frozen String

文字列の解凍(Ruby 2.2以前)

凍結されたオブジェクトは解凍(内容の変更を再許可)できない。凍結状態を含め、変更を禁ずるのが「凍結」だからである。

そのかわり、Object#dup で、凍結されたオブジェクトとほぼ同じ内容の非凍結オブジェクトが得られる。

前述の通り、String は Object を継承しているので、String#dup で非凍結文字列が得られる。

s = 'hoge'
s.freeze
s2 = s.dup  # => "hoge"
s2.frozen?  # => false

また、String.new(frozen_string) でも、frozen_string とほぼ同じ内容の非凍結文字列が得られる。

s = 'hoge'
s.freeze
s2 = String.new(s)  # => "hoge"
s2.frozen?          # => false

ただ、これらのメソッドは、「非」凍結文字列のコピーが欲しいときにも使われるため、解凍を意図していることがコード上からは分かりづらい。

文字列の解凍(Ruby 2.3以降)

Ruby 2.3 で、String#+@ が導入された。インスタンスが凍結されている場合は同内容の非凍結文字列が得られ、凍結されていない場合はインスタンス自身が得られる。

s = 'hoge'
s.freeze
s2 = +s     # => "hoge"
s2.frozen?  # => false

対称的な挙動の String#-@ も用意されている。

s = 'hoge'
s.frozen?   # => false
s2 = -s     # => "hoge"
s2.frozen?  # => true

これらのメソッドは意図が明確なので、コード読解の障害にならないだろう。

一見、どちらが凍結でどちらが解凍か忘れてしまいそうだが、「オブジェクトの温度が低く(-)なれば凍結され、高く(+)なれば解凍される」と考えれば覚えやすい。

22
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?