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