Ruby 为什么可以';不能用符号调用受保护的方法来处理吗?

Ruby 为什么可以';不能用符号调用受保护的方法来处理吗?,ruby,Ruby,鉴于以下类别: class Foo def a dup.tap { |foo| foo.bar } end def b dup.tap(&:bar) end protected def bar puts 'bar' end end 似乎Foo#a和Foo#b应该是等效的,但它们不是: > Foo.new.a bar => #<Foo:0x007fe64a951ab8> > Foo.new.b N

鉴于以下类别:

class Foo
  def a
    dup.tap { |foo| foo.bar }
  end

  def b
    dup.tap(&:bar)
  end

  protected

  def bar
    puts 'bar'
  end
end
似乎
Foo#a
Foo#b
应该是等效的,但它们不是:

> Foo.new.a
bar
 => #<Foo:0x007fe64a951ab8>

> Foo.new.b
NoMethodError: protected method `bar' called for #<Foo:0x007fe64a940a88>
>Foo.new.a
酒吧
=> #
>Foo.new.b
NoMethodError:为调用受保护的方法'bar'#
这有什么原因吗?这是虫子吗


在Ruby 2.2.3p173上测试,让我们首先注意,在Ruby中,您可能知道,在类
Foo
上声明的方法
a
中,我可以在
Foo
的任何实例上调用受保护的方法

Ruby如何确定我们是否在类
Foo
上声明的方法中?要理解这一点,我们必须深入研究方法调用的内部。我将使用MRI版本2.2中的示例,但可能其他版本中的行为和实现是相同的(不过,我希望看到在JRuby或Rubinius上测试的结果)

Ruby是用中文做这个的。正如注释所示,
self
用于确定是否可以调用受保护的方法<代码>自我从当前线程的调用帧信息中检索。然后,在中,我们检查
self
的这个值是否属于定义了受保护方法的同一类

块在某种程度上混淆了这个问题。请记住,Ruby方法中的局部变量由该方法中声明的任何块捕获。这意味着在块中,
self
与调用该方法的
self
相同。让我们看一个例子:

class Foo
    def give_me_a_block!
        puts "making a block, self is #{self}"
        Proc.new do
            puts "self in block0 is #{self}"
       end
    end
end

proc = Foo.new.give_me_a_block!

proc.call
运行此命令时,我们会看到
Foo
的同一个实例在所有级别上都是相同的,尽管我们从一个完全不同的对象调用了proc

因此,现在我们了解了为什么可以从方法中的块中对同一类的另一个实例调用受保护的方法

现在让我们看看为什么用
&:bar
创建的进程不能这样做。当我们在方法参数之前放置一个
&
符号时,我们做了两件事:指示ruby将此参数作为块传递,并指示ruby调用
来对其进行处理

这意味着调用方法
Symbol\u proc
。这个方法是用C实现的,但是当我们调用一个C方法时,当前帧上指向
self
的指针就变成了该C方法的接收者——在这种情况下,它变成了符号
:bar
。因此,我们正在查看
foo
的实例,就好像我们在类符号的方法中一样,我们不能调用受保护的方法


这是一口,但希望它有足够的意义。如果您对我如何改进有任何建议,请告诉我

这是一个很好的问题。希望有人能给我们一些启发。这的确是个好问题。我能看到的唯一区别是,在第一个块中对局部变量调用
bar
,但在没有变量的情况下使用proc调用它。尽管如此,我还是想知道这是否有一个很好的理由。在没有
foo
变量的情况下进行了测试,但仍然是一样的。我认为这一定与如何调用proc有关,尽管我认为这两种方法应该输出相同的结果。