[英]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.