2009-09-15 12 views
19

Örnek_eval ile Foo tanımladığınızda fark var mı:. . .'get self', example_eval ile aynı mıdır?

class Foo 
    def initialize(&block) 
     instance_eval(&block) if block_given? 
    end 
    end 

. . . ya da 'verim öz' ile: Yani 'yield self'

x = Foo.new { def foo; 'foo'; end } 
x.foo 

Foo.new sonra blok daima bağlamında değerlendirilmektedir anlamına gelir:

class Foo 
    def initialize 
    yield self if block_given? 
    end 
end 

Her iki durumda da bunu yapabilirsiniz Foo sınıfı.

Bu doğru mu?

cevap

14

İki kod parçanız çok farklı şeyler yapar. Instance_eval kullanarak, nesneyi bağlamında bloğu değerlendiriyorsunuz. Bu, def kullanılarak bu nesne üzerindeki yöntemleri tanımlayacağı anlamına gelir. Ayrıca, bloğun içinde bir alıcı olmayan bir yöntem çağırmak, onu nesnenizde çağıracaktır.

Kendinizi yitirirken, kendini bloğa bir argüman olarak geçiriyorsunuz, ancak bloğunuz herhangi bir argüman almıyor olduğundan basitçe yok sayılır. Yani bu durumda benlik veren şey, hiçbir şey vermeyerek aynı şeyi yapar. def tam olarak, blokun dışında bir def gibi davranır, bu da kendiliğinden, yöntemi tanımladığınız şeyi değiştirmez. Yapabilecekleriniz:

class Foo 
    def initialize 
    yield self if block_given? 
    end 
end 
x = Foo.new {|obj| def obj.foo() 'foo' end} 
x.foo 

Örnek_eval arasındaki fark, alıcıyı açıkça belirtmeniz gerektiğidir.verim ile versiyonda

obj blokta bu durumda yeni oluşturulan Foo örneğidir olduğu vermiştir nesneyi olacak:

Düzenleme netleştirmek için. Kendilik aynı değere sahipken, bloğun dışında kalmıştı. Bloğun içindeki instance_eval sürüm self ile yeni oluşturulan Foo örneği olacaktır.

+0

"Açıklığa kavuşturmak için düzenleyin" ifadesinde, kendinizin bloğun içindeki objeye verildiğini mi kastediyorsunuz? Belki de sadece farklı bir yoldan okuyorum ama başlangıçtaki nesneyi görüyorum, kendiliğinden bloğa 'obj' denir ve sonra bloğun içinde foo'nun kendiliğinden obj üzerinden tanımlanması yöntemi vardır. – uzo

+1

Eminim, aynı şeyi kastediyoruz. "Yeni yaratılan Foo örneğini" yazdım çünkü başlatma yönteminin içinde (yeni oluşturulan Foo örneğidir) blok içinde kendiliğiyle aynı değildir ve eğer "ben" derken, hangisini kastettiğiniz belirsizdir. – sepp2k

4

sadece irb dışında kullanılan özel olarak benim tadı yeni biraz vardırverim kullanma öz anahtar kelimeyi yorumlarla

den

class Foo 
    def initialize 
    yield if block_given? 
    end 
end 

Güncelleme bırakabilirsiniz.

class Foo 
    def initialize(&block) 
    instance_eval(&block) if block_given? 
    end 
end 
x = Foo.new { def foo; 'foo'; end }    
#=> #<Foo:0xb800f6a0>            
x.foo #=> "foo"               
z = Foo.new #=> #<Foo:0xb800806c>            
z.foo #=>NoMethodError: undefined method `foo' for #<Foo:0xb800806c> 

Kontrol yanı bu bir:

class Foo2 
    def initialize 
    yield if block_given? 
    end 
end 
x = Foo2.new { def foo; 'foo'; end } #=> #<Foo:0xb7ff1bb4> 
x.foo #=> private method `foo' called for #<Foo2:0xb8004930> (NoMethodError) 
x.send :foo => "foo" 
z = Foo.new #=> #<Foo:0xb800806c> 
z.send :foo => "foo" 

yapabilirsiniz gibi

Ancak yaklaşımı ve verim yaklaşımı instance_eval arasında büyük ve önemli bir fark vardır, bu pasajı kontrol fark, birincisi, başlatılan nesneye bir tekil yöntemi olan foo ekleyerek e daha sonra Object sınıfının tüm örneklerine özel bir yöntem ekliyor.

+2

"Farkı görebildiğiniz gibi, birincisi, başlatılan nesneyi bir tekton yöntemi foo eklerken, daha sonra bu yöntemi Foo2 sınıfının tüm örneklerine ekliyor." Nesne (ve gerçek ruby ​​(irb aksine) özel bir yöntem olarak ekleyecektir, böylece x.foo veya z.foo yapamazsınız, sadece foo). Diğer bir deyişle, tam olarak blokun dışına yazmışsınız gibi davranır (yöntem, elbette ki bir şey olmadıkça, hiçbir durumda olmaz). – sepp2k

+0

Kesinlikle doğru, teşekkürler – khelll

+0

Ruby 1.9'da, özel yöntem tanımını alamıyorsunuz. Bunun yerine, x = Foo2.new {def foo; 'Foo'; Nesne üzerinde 'foo' yöntemini tanımlar (sepp2k olarak söylenir). Diyorsunuz da bunu görebilirsiniz: x.methods (yanlış) .grep/foo/ # => [] Object.new.foo # => "foo" –

7

Bunlar farklıdır. yield(self), instance_eval(&block)'un yaptığı sırada, self değerini bloğun içinde değiştirmez.

class Foo 
    def with_yield 
    yield(self) 
    end 

    def with_instance_eval(&block) 
    instance_eval(&block) 
    end 
end 

f = Foo.new 

f.with_yield do |arg| 
    p self 
    # => main 
    p arg 
    # => #<Foo:0x100124b10> 
end 

f.with_instance_eval do |arg| 
    p self 
    # => #<Foo:0x100124b10> 
    p arg 
    # => #<Foo:0x100124b10> 
end 
+0

ikinci 's arg' yazdırmalısınız' nil 'değil' # '. – sepp2k

+0

1.8.7'de, Foo örneği yazdırılır. Bunun nil olmayacağını düşündüm, neden olmadığından emin değilim. –

+0

1.9'da sıfır yazdırıldı. Foo örneğini basan 1.8.7 için herhangi bir açıklama göremiyorum. Çıktının yanlış yazılmadığından emin misin? – sepp2k

İlgili konular