web-dev-qa-db-ja.com

なぜどこにでも凍結定数があるのですか?

ラックやレールなど、多くの有名なリポジトリからそのようなスタイルを簡単に見つけることができます。

たとえばラック内

PATH_INFO      = 'PATH_INFO'.freeze
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
SCRIPT_NAME    = 'SCRIPT_NAME'.freeze
QUERY_STRING   = 'QUERY_STRING'.freeze
CACHE_CONTROL  = 'Cache-Control'.freeze
CONTENT_LENGTH = 'Content-Length'.freeze
CONTENT_TYPE   = 'Content-Type'.freeze

Railsの別の例

HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
HTTP_IF_NONE_MATCH     = 'HTTP_IF_NONE_MATCH'.freeze
HTTP_IF_NONE_MATCH     = 'HTTP_IF_NONE_MATCH'.freeze

なぜこれらの定数文字列がフリーズするのだろうか。これらはすべて定数であるため、インスタンスは1つだけにする必要があります。もちろん、同じシングルトンインスタンスを参照するために"foo".freezeをどこかに置くこともできますが、人々は通常、代わりにHTTP_IF_MODIFIED_SINCEのようなリテラル変数名を記述します。

それで、私の意見では、#freezeを使用しても違いはありません。それでは、なぜ人々は定数をフリーズするのでしょうか。

24
Jian Weihang

すでに初期化されている定数に値を再割り当てすると、Rubyが警告を出力するのは正しいことです。

> FOO = 'foo'
> FOO = 'bar'
# :2: warning: already initialized constant FOO
# :1: warning: previous definition of FOO was here
> FOO
# => "bar"

ただし、定数の値を変更することからの保護はありません。 freezeのない例:

> FOO = 'foo'
> FOO[1] = '-'
> FOO
# => "f-o"

ただし、freezeを使用すると、定数の値が変更されないように保護できます。 freezeの例:

> FOO = 'foo'.freeze
> FOO[1] = '-'
# => RuntimeError: can't modify frozen String
32
spickermann

人気のあるプロジェクトでこの定数の一貫したフリーズが見られる理由の1つは、コードアナライザーである Rubocop を使用していることです。

@spickermannが前述した理由により、定数を変更できないようにするのは標準のRubocop rule です。

1
Eric Duminil