Ruby 是';屈服自我';与实例评估相同?
如果使用实例\u eval定义Foo有什么区别:强>Ruby 是';屈服自我';与实例评估相同?,ruby,Ruby,如果使用实例\u 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 f
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类的上下文中进行计算
这是否正确?您只需删除self关键字即可
class Foo
def initialize
yield if block_given?
end
end
根据评论更新
使用产量对我来说有点新鲜,特别是在irb之外使用时
然而,instance\u 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-Foo
def初始化(&block)
如果给定块,则实例评估(&block)?
结束
结束
x=Foo.new{def Foo;'Foo';end}
#=> #
x、 foo#=>“foo”
z=Foo.new#=>#
z、 foo#=>NoMethodError:未定义的方法'foo'用于#
也请检查此项:
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"
class-Foo2
def初始化
如果给定块_,收益率是多少?
结束
结束
x=Foo2.new{def foo;'foo';end}#=>#
x、 foo#=>为#调用的私有方法'foo'(NoMethodError)
x、 发送:foo=>“foo”
z=Foo.new#=>#
z、 发送:foo=>“foo”
正如您所看到的,区别在于前者是向正在初始化的对象添加一个单例方法foo,而后者是向对象类的所有实例添加一个私有方法。它们是不同的<代码>收益率(self)不会更改块内
self
的值,而instance\u 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
class-Foo
def与_产量
产量(自我)
结束
带有实例的def评估(&block)
实例求值(&block)
结束
结束
f=Foo.new
f、 具有| do | arg的|
p自我
#=>主要
p精氨酸
# => #
结束
f、 带有|实例|评估do |参数|
p自我
# => #
p精氨酸
# => #
结束
您的两段代码的功能截然不同。通过使用instance_eval,可以在对象的上下文中计算块。这意味着使用def将在该对象上定义方法。这还意味着在块内没有接收器的情况下调用方法将在对象上调用它
当屈服于self时,您将self作为一个参数传递给块,但是由于块不接受任何参数,因此它将被忽略。因此,在这种情况下,屈服于自我与不屈服于任何东西是一样的。这里的def
的行为与块外的def
的行为完全相同,实际上不会更改您在其上定义方法的内容。你能做的是:
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 version
self
,块内将是新创建的Foo实例。“正如您所看到的,不同之处在于前者将一个单一方法Foo添加到被初始化的对象中,而后者将该方法添加到类Foo2的所有实例中。”,后者是将方法添加到对象中(在真正的ruby中(与irb相反),它将把它作为私有方法添加,所以您不能执行x.foo或z.foo,只执行foo)。换句话说,def的行为就像是在块外编写的一样(当然,除非方法不产生任何结果,在这种情况下不会发生任何事情)。相反,x=Foo2.new{def foo;'foo';end}将在对象上定义方法“foo”(正如sepp2k所说)。你可以这样说:x.methods(false).grep/foo/#=>[]Object.new.foo#=>“foo”第二个p arg
应该打印nil
,而不是
。在1.8.7中,打印foo实例。我以为它也会是零,不知道为什么不是。在1.9中,零被打印出来。我看不到任何关于1.8.7打印Foo实例的解释。您确定没有误读输出吗?1.8.7打印Foo实例,因为self在1.8.7中作为未记录的参数传递给instance_eval。这个未记录的参数在修订版9937()中被删除,并在修订版10063()中重新添加,使其及时进入树中进行1.8.7()快速更新,在1.9.2和1.9.3中,Foo实例被打印。在“编辑以澄清”中,您的意思是self被提交给块中的obj吗?也许我只是用另一种方式来理解它,但我看到对象被初始化,self作为'obj'被交给块,然后在块内,方法foo通过obj在self上定义。我很确定,我们的意思是一样的。我写了“新创建的Foo实例”,因为initialize方法中的self(即新创建的Foo实例)与块中的self不同,如果您只说“self”,那么不清楚您指的是哪一个。