2009-04-02 19 views
12

ı Ruby sınıf var diyelim: Ben denemek ve MyClass.property=x yaparsanızSınıf.property = x'in x dışında bir şey döndürmesi mümkün mü?

class MyClass 
    def self.property 
    return "someVal" 
    end 

    def self.property=(newVal) 
    # do something to set "property" 
    success = true 

    return success # success is a boolean 
    end 
end 

, bütün ifadenin dönüş değeri x zaman. Boolean "başarı" değerini döndürmek için bir çok C-temelli/esinlenmiş dilde bir sözleşmedir - bunu Ruby'de "eşittir sözdizimi" kullanarak bir dizge için yapmak mümkün mü? Ayrıca, eğer bu mümkün değilse, neden olmasın? "Eşit ayarlayıcı" işleminin bir değer döndürmesine izin verecek düşecek bir olumsuzluk var mı?

cevap

11

Tek olumsuz zincirleme atama semantiğini kopar diye:

$ irb 
irb(main):001:0> x = y = 3 
=> 3 
irb(main):002:0> p x 
3 
=> nil 
irb(main):003:0> p y 
3 
=> nil 
irb(main):004:0> 

düşünün: Bu çalıştı eğer (sağ birleşim) beklediği gibi

x = MyClass.property = 3 

Sonra x true alacaktı. Arayüzünüzü kullanan ve tipik semantiklere alışkın olanlar için bu bir sürpriz olabilir.

Ayrıca ben, paralel atama düşünmeye var mesela:

x, y = 1, 2 

Görünüşe göre bu ifadeden dönüş değeri ben paralel atamaları :)

zincirleme olmayacak galiba ... implementation specific olduğunu Güzel soru!

+0

, zincirleme atama semantik kıracak: şey kolayca göz ardı edilebilir bir dönüş değeri, aksine ters giderse Sonra bütün INVOKER'LAR idare gerekir ". Rampiyonun cevabı netleştikçe, durum böyle değildir: bir tahsis yönteminin dönüş değeri normal olarak dikkate alınmaz. Martin'in söylediği şey “dil bunu yapmanıza izin vermez; eğer öyleyse, zincirleme ödev anlamını bozarsınız”. –

5

Ruby uzmanı değilim ama korkarım ki bu vaka için korkuyorum. Özel bir alanın değerini ayarlamak için bir özellik belirleyici yalnızca, sonuç kodları döndürme gibi herhangi bir yan etkiye sahip olmamalıdır.

Bu işlevselliği istiyorsanız, dizgeyi unutun ve TrySetProperty adlı yeni bir yöntem yazın veya özelliği ayarlamaya ve bir boole döndürmeye çalışan bir yöntem yazın.

7

Martin'in dediği gibi, bu da zincirleme zincirini kırıyor.

Çalışmak üzere ruby ​​atama yöntemlerinin tanımlanması yolu MyClass.property = 3(lambda { |v| MyClass.send('property=', v); v })[3] eşdeğerine genişletir (gerçekten değil, ama bu, zincirin nasıl çalıştığını gösterir). Ödevin dönüş değeri her zaman atanan değerdir. Eğer MyClass#property= yöntem sonucu görmek istiyorsanız

ardından #send kullanın:

irb> o = Object.new 
=> #<Object:0x15270> 
irb> def o.x=(y) 
irb> @x = y+1 
irb> puts "y = #{y}, @x = #@x" 
irb> true 
irb> end 
=> nil 
irb> def o.x 
irb> puts "@x = #@x" 
irb> @x 
irb> end 
=> nil 
irb> o.x = 4 
y = 4, @x = 5 
=> 4 
irb> o.x 
@x = 5 
=> 5 
irb> o.send('x=', 3) 
y = 3, @x = 4 
=> true 

Ancak, bunu yapmak için yakut yolu istisnalar dışında büyüktür - atama sırasında yanlış giderse, bir zam istisna. Böyle bir erişimci tanımlı eğer

Ben ilk" olarak okumak
# continued from above... 
irb> def o.x=(y) 
irb> unless y.respond_to? :> and (y > 0 rescue false) 
irb>  raise ArgumentError, 'new value must be > 0', caller 
irb> end 
irb> @x = y + 1 
irb> puts "y = #{y}, @x = #@x" 
irb> end 
=> nil 
irb> o.x = 4 
y = 4, @x = 5 
=> 4 
irb> o.x = 0 
ArgumentError: new value must be > 0 
    from (irb):12 
    from :0 
irb> o.x = "3" 
ArgumentError: new value must be > 0 
    from (irb):13 
    from :0 
irb> o.x 
@x = 5 
=> 5 
İlgili konular