2009-03-21 7 views
4

次の2つの例では、同じことを行います。定数Stringを作成し、concatメソッドを使用してそれを変更します。それは定数なので、私はコンパイラの警告を期待していますが、代入演算子を使用すると、2番目の例で1つしか受け取りません。どうしてこれなの?代入演算子がないと、コンパイラの警告なしにRuby定数を変更できないのはなぜですか?

X = "hello" 
X.concat(" world") 
puts X # no warning 

X = "hello" 
X = X.concat(" world") 
puts X # warning: already initialized 

concatメソッドが代わりに文字列を変更しているのでassigment演算子を使用する必要がないため、それは、私がどうなるのか正常です。したがって、なぜ代入演算子が存在すると、コンパイラはこれら2つの演算を異なるものとして識別させるのでしょうか?

+0

厳密に言うと、コンパイラの警告ではなく、インタプリタの警告です。 Rubyは通常はコンパイルされません。 –

答えて

6

これは、新しいXを再定義するためです。定数を再定義すると、「既に初期化されました」というエラーが表示されます。最初の例では、Xを再定義していないのでこのエラーは表示されません。

+1

右のルビ定数は不変ではなく、単にオブジェクトを切り替える必要がないということです。 – rampion

7

Rubyでは、変数は基本的に、オブジェクトを含むメモリ内の場所へのポインタであり、オブジェクト自体ではありません。 2番目の例では、最初の行(X = "hello")のオブジェクトを指すように定数Xを初期化していて、2行目で定数を再度初期化していますが、すでにオブジェクトを指しています。エラー。

定数の不変性はオブジェクトを変更できないことを意味するものではなく、という別のオブジェクトを指すように変更することはできません。

0

これは、定数XStringオブジェクトへの参照を格納しているためです。最初の例では、Stringオブジェクトの内部状態は変更していますが、定数に格納されている参照は変更していません。 2番目の例では、定数によって格納された参照をconcatメソッドから返された新しいStringオブジェクトに変更しています。

PickAxeの本はこれをhereで説明しています。

4

あなたの文字列が「本物」の定数にしたい場合は、「凍結」を試してみてください。

X = "foo".freeze  # => "foo" 
X.concat("bar") 

TypeError: can't modify frozen string 
    from (irb):2:in `concat' 
    from (irb):2 

私は本当にThe Ruby Programming Langugeを読むことをお勧めします。

+0

本のリンクをありがとう、私はちょうど私のSafariの本棚に追加しました。 –

+0

これは、 "奇妙な"、おそらく直感的ではない(少なくともC++/Javaプログラマーのために)ルビーコーナーを理解するのに役立ちます。 "Ruby Hacking Guide"(http://rhg.rubyforge.org/)は、特にRubyのメタプログラミングがどのようにしてボットの下で動作するかを理解したいときには、見逃せない場所です。 –

関連する問題