Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 是';屈服自我';与实例评估相同?_Ruby - Fatal编程技术网

Ruby 是';屈服自我';与实例评估相同?

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

如果使用实例\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 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”,那么不清楚您指的是哪一个。