簡體   English   中英

'yield self'和instance_eval一樣嗎?

[英]Is 'yield self' the same as instance_eval?

如果用instance_eval定義Foo,有什么區別嗎:

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

或者'屈服自我':

class Foo
  def initialize
    yield self if block_given?
  end
end

無論哪種情況,您都可以這樣做:

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

所以' yield self '意味着Foo.new之后的塊總是在Foo類的上下文中進行評估。

它是否正確?

你的兩段代碼做了很多不同的事情。 通過使用instance_eval,您將在對象的上下文中評估塊。 這意味着使用def將定義該對象的方法。 它還意味着在塊內調用沒有接收器的方法將在您的對象上調用它。

在屈服於self時,你會將self作為參數傳遞給塊,但由於你的塊不帶任何參數,所以它被忽略了。 所以在這種情況下,屈服於自我就會產生同樣的東西。 這里的def就像塊外的def一樣,屈服於self並不會實際改變你定義方法的內容。 你能做的是:

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

與instance_eval的區別在於您必須明確指定接收方。

編輯澄清:

在帶有yield的版本中,塊中的obj將是生成的對象,在這種情況下是新創建的Foo實例。 雖然self將具有與塊外部相同的值。 使用instance_eval版本,塊內的self將是新創建的Foo實例。

它們是不同的。 yield(self)不會改變塊內self的值,而instance_eval(&block)則會改變。

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

你可以刪除self關鍵字

class Foo
  def initialize
    yield if block_given?
  end
end

從評論更新

使用產量對我來說有點新鮮,特別是在irb外使用時。

但是, instance_eval方法和yield方法之間存在重大差異,請查看以下代碼段:

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>

檢查一下:

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"

正如您所看到的那樣,區別在於前者正在向正在初始化的對象添加單例方法foo ,而后者則向Object類的所有實例添加私有方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM