2013-06-12 17 views
11

Ruby'yi öğreniyorum ve değişkenlerle Object#freeze yöntemini kullanırken ilginç bir davranış buldum.Ruby'de donma değişkenleri çalışmıyor

Bir değişkeni dondurduktan sonra (Fixnum veya Array), hala değiştirebilirim! Bu garip, endişelendiğim sürece bu olmamalı ve TypeError yükseltilmelidir.

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

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

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

aynı dizide içindir:

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

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

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

Ama dondurma sonra diziye bir şey itmek çalıştığınızda beklendiği gibi, bu bir arror yükseltir: Burada

kod bu

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

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

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

Birisi bana bu sorunu açıklayabilir mi? Garip görünüyor. Ben, Nesneleri değil değişkenleri dondurmak Windows XP ve üzeri Yakut 1.9.3-P429

+1

meraklı:

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 

Burada rasyonel okuyabilirsiniz: Bir nesnenin iç yapıları açığa zaman, ne yaptığını dikkat yoksa bu zor sizi ısırabilir - Neden "test" = "666": P – sircapsalot

+0

Bu, donmanın yaptığı şey değil; Tam olarak amaçlandığı gibi çalışıyor. Değişmez değerler gibi değişmez değerleri donduramazsınız ve kesinlikle değişkenleri "donduramazsınız", böylece yeni değerlere ayarlanamazlar. Sadece nesneleri dondur. – meagar

+1

@meagar: Değişkenleri dondurabilirsiniz. Sadece anlamsız çünkü zaten değiştirilemezler. Ama 5.freeze '' 5.Frozen? '' True' döndürdüğü anlamında çalışır. –

cevap

32

kullanıyorum

Düzenleme Eğer donmuş bir nesneyi güncellemek olamaz yani ama aynı değişkene yeni bir nesne atayabilirsiniz . Şunu bir düşünün:

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] 

bir kenara: Bunların sabit nesneler olduklarından, Fixnum s dondurmak için oldukça işe yaramaz.

+0

Eh, 'donma değişkenleri'ne atıfta bulunarak özverili olmak, aklımda olan şey elbette donmuş nesnelerdi (değişken sadece koddaki bir etiket) Bu 'donmak' için hiçbir şey yapmaz :)) Tamam, şimdi bu donma işinin nasıl olduğunu anlıyorum, ama yine de biraz kafam karıştı, neden yeni bir nesne atamak hiçbir şey yükseltmiyor. Bunun bir şekilde, örneğin gibi, 'aliasing' bağlı mı: #Biz bellekte 1 nesne ve buna 1 adlar var obj1 = Object.new obj1.freeze obj1 = Object.new # obj1 şimdi başka bir nesneye işaret, ancak ilk nesne için bellek hala "donmuş" mu? Doğru mu anladım? –

+0

@FilipZymek Anladım. :) – toro2k

+0

Tamam, bu mükemmel bir anlam ifade ediyor, teşekkürler! –

17

Ruby'de değişkenler nesnelere başvurulardır. Nesneyi dondur, değişkeni değil. diziler için + yeni bir nesne oluşturur çünkü

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

bir hata olmadığını da lütfen unutmayın.

+0

Dizgilerle aynı. Cevap için +1. '' ruby ​​ a = 'test'.freeze # => "test" a.frozen? # => true a << '1' # RuntimeError: donmuş olarak değiştirilemez Dize a + = '1' # => "test1" '' ' – kode

12

Diğer iki yanıtta belirtildiği gibi, değişkenlerden ziyade nesneleri dondurursunuz.

Ebeveyn dondurulduğunda donmayan alt nesneler üzerine bir not eklemek istiyorum.

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

+0

bu yararlı ipucu teşekkürler! –