2013-06-12 10 views
11

私はRubyを学んでいますが、Object#freezeメソッドを変数に使用すると面白い動作が見つかりました。Rubyのフリーズ変数が機能しない

変数(FixnumまたはArrayのいずれか)をフリーズした後でも、まだ変更できます。それは私がこれについて起こるべきでない限り、TypeErrorが提起されるべきであるので、奇妙です。同じアレイにある

test = 666 
var = 90 
#ok 
var += 5 

puts "var.frozen? #{var.frozen?}"  
var.freeze  
puts "var.frozen? #{var.frozen?}" 

var = test 
puts "var = #{var}" 

:ここ

は私のコードです

test = [666] 
var = [90] 
#ok 
var += [5] 

puts "var.frozen? #{var.frozen?}"  
var.freeze  
puts "var.frozen? #{var.frozen?}" 

var = test 
puts "var = #{var}" 

しかし、私は凍結後のアレイに何かをプッシュしようとすると、期待どおり、それは、arrorが発生します。

test = [666] 
var = [90] 
#ok 
var += [5] 

puts "var.frozen? #{var.frozen?}"  
var.freeze  
puts "var.frozen? #{var.frozen?}" 

var << test 
puts "var = #{var}" 

誰かがこの問題を説明できますか?奇妙に思える。私は、あなたがオブジェクトではなく、変数を凍結するのWindows XP + Rubyの1.9.3-p429

+1

好奇心:

class A attr_accessor :var end a = A.new a.var = [] a.freeze a.var = [] # this fails as expected a.var << :a # this works, raises no errors, and no warnings 

はあなたがここに合理的について読むことができます:あなたは、オブジェクトの内部構造を露出させたときに、やっていることに注意を払っていない場合、これは、ハード、あなたをかむことができます - なぜ 'test' =' 666'なのですか?P – sircapsalot

+0

これはフリーズするものではありません。意図どおりに動作しています。リテラル番号のような不変の値をフリーズすることはできず、変数を「フリーズ」することができないため、新しい値に設定することはできません。オブジェクトはフリーズするだけです。 – meagar

+1

@meagar:immutablesをフリーズすることができます。彼らはとにかく変更することができないので、ちょうど無意味です。しかし、「5.フリーズ」は「5.フリーズ」が「真」を返すという意味では機能します。 –

答えて

32

を使用しています

編集あなたが凍結されたオブジェクトを更新することはできませんつまりができますが、同じ変数に新しいオブジェクトを割り当てることができます。余談として

a = [1,2,3] 
a.freeze 
a << 4 
# RuntimeError: can't modify frozen Array 

# `b` and `a` references the same frozen object 
b = a 
b << 4  
# RuntimeError: can't modify frozen Array 

# You can replace the object referenced by `a` with an unfrozen one 
a = [4, 5, 6] 
a << 7 
# => [4, 5, 6, 7] 

::彼らは不変オブジェクトなので、Fixnum Sを凍結することは非常に無駄ですこれを考えてみましょう。

+0

「凍結変数」を参照することで駄目になってしまいます。もちろん、私は凍結したオブジェクトを念頭に置いていました(変数はコード内のラベルなのでそれは「凍らない」という意味ではありません:)) これで、このフリーズの仕事はどうなっているのですか?まだ、私はまだ少し混乱しています。これは何とか例えばのように、「エイリアス」に接続されている: #WEは、メモリ内の1つのオブジェクトとそれに1つの別名を持つ OBJ1 = Object.new obj1.freeze OBJ1 = Object.new#obj1が今別のオブジェクトを指し、最初のオブジェクトのメモリはまだ "フリーズ"されていますか? 私はそれを正しくしていますか? –

+0

@FilipZymekあなたはそれを持っています。 :) – toro2k

+0

これは完璧な感覚です、ありがとう! –

17

Rubyでは、変数はオブジェクトへの参照です。変数ではなくオブジェクトをフリーズします。アレイ用+は、新しいオブジェクトを作成するため

a = [1, 2] 
a.freeze 
a += [3] 

はエラーではないことにも注意してください。

+0

文字列と同じです。 +1の答え。 '' 'ruby a = 'テスト'。フリーズ#=>「テスト」 a.frozen? #=> true a '1'#RuntimeError:フリーズした文字列を変更できません a + = '1'#=>「test1」 '' ' – kode

12

他の2つの答えで説明したように、変数ではなくオブジェクトをフリーズします。

親がフリーズしたときにフリーズしない子オブジェクトにメモを追加したいと思います。

https://bugs.ruby-lang.org/issues/6037

+0

これは便利なヒントです! –

関連する問題