Ruby は動的言語です。静的なコンパイルはなく、最終的に誰が変数にアクセスして変更するかをインタープリターが事前に知ることは非常に困難です。
次の例を見てみましょう。あなたが持っているstring
str = "foo"
その後、コードの後半で
str.upcase!
# => "FOO"
この例は、単純なパーサーでさえ、文字列が変更されていることを理解するのは非常に簡単です。しかし、もう少し複雑にしましょう
str = "foo"
method = ["up", "case"]
str.send((method << "!").join)
# => "FOO"
これは前とまったく同じ結果を生成していますが、メソッドはスクリプトで静的にコーディングされていません。代わりに、実行時に文字列に対して動的に実行される計算の結果です。
でもちょっと待って、もっと複雑にしましょう。
str = "foo"
method = [ARGV.first, "case"]
str.send((method << "!").join) if ARGC.to_i > 0
# => "FOO"
この場合、コマンド ラインから引数を渡すと仮定すると、変換メソッドが計算され、文字列に適用されます。
ご想像のとおり、どちらの場合も、変更されることを知る唯一の方法str
は、実際にコードを実行することです。
これらの例は、質問の2番目の部分にも答える必要があります
インタープリターが実行を開始すると、コードはどのようにそのような文字列を変更できますか? 「abcd」を凍結する必要があると言うなら、それを変更する何らかの方法があるに違いありません。
補足として、「凍結された文字列リテラル」機能が最近進化し、変数に としてフラグを立てるだけで十分であることを指摘しておきますfrozen
。
Ruby 2.1 では、"str".freeze
すべての呼び出しで 1 つの共有凍結文字列を返すようにコンパイラによって最適化されています。代わりの "str"f 構文が最初に実装されましたが、後に元に戻りました。