ruby – 为什么不能使用符号来调用protected方法?

前端之家收集整理的这篇文章主要介绍了ruby – 为什么不能使用符号来调用protected方法?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
给出以下类:
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>

有没有理由呢?这是一个bug吗?

测试了Ruby 2.2.3p173

解决方法

让我们从Ruby开始,你可能知道,在Foo类中声明的方法中,我可以在任何Foo实例上调用受保护的方法.

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

Ruby在rb_call0中这样做.正如评论所示,self用于确定我们是否可以调用受保护的方法.自己在rb_call从当前线程的调用帧信息中检索.然后,在rb_method_call_status,我们检查自己的这个值是否是一个保护方法被定义的同一个类.

块有点混淆.请记住,Ruby方法中的局部变量由该方法中声明的任何块捕获.这意味着在块中,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.

所以,现在我们明白为什么可以在一个方法的一个块内从同一个类的另一个实例上调用一个protected方法.

现在我们来看看为什么用&:bar创建的proc不能这样做.当我们放置&在方法参数之前签名,我们做两件事情:指示ruby将此参数作为块传递,并指示它调用to_proc.

这意味着调用Symbol#to_proc的方法.该方法在C中实现,但是当我们调用C方法时,当前帧上的指向self的指针将成为该C方法的接收者 – 在这种情况下,它成为符号:bar.所以我们正在看一下我们得到的foo实例,就好像我们在类Symbol中的方法一样,我们不能调用一个protected方法.

这是一口气,但希望它足够有意义.如果您有任何建议,如何改善它,请告诉我们!

猜你在找的Ruby相关文章