gpt4 book ai didi

ruby - 为什么不能使用要处理的符号调用 protected 方法?

转载 作者:数据小太阳 更新时间:2023-10-29 06:39:42 27 4
gpt4 key购买 nike

给定以下类:

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

def b
dup.tap(&:bar)
end

protected

def bar
puts 'bar'
end
end

看起来 Foo#aFoo#b 应该是等价的,但它们不是:

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

> Foo.new.b
NoMethodError: protected method `bar' called for #<Foo:0x007fe64a940a88>

这是有原因的吗?这是错误吗?

在 Ruby 2.2.3p173 上测试

最佳答案

让我们首先注意,在 Ruby 中,您可能知道,在类 Foo 上声明的方法 a 中,我可以在 任何对象上调用 protected 方法 Foo 的实例。

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

Ruby 在 rb_call0 中做到了这一点.正如注释所暗示的那样,self 用于确定我们是否可以调用 protected 方法。 selfrb_call 中检索来自当前线程的调用帧信息。然后,在 rb_method_call_status ,我们检查 self 的这个值是否属于定义了 protected 方法的同一类。

block 在某种程度上混淆了这个问题。请记住,Ruby 方法中的局部变量由该方法中声明的任何 block 捕获。这意味着在该 block 中,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。

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

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

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

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

关于ruby - 为什么不能使用要处理的符号调用 protected 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34123583/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com