7

在顶层,方法定义应该导致私有方法 on Object,并且测试似乎证明了这一点:

def hello; "hello world"; end

Object.private_instance_methods.include?(:hello) #=> true
Object.new.send(:hello) #=> "hello world"

但是,以下也适用于顶层(self.meta是 的特征类main):

self.meta.private_instance_methods(false).include?(:hello) #=> true

似乎该hello方法同时定义在 main 和 on 的特征类上Object。这是怎么回事?请注意,要从方法列表false中排除超类方法的参数。private_instance_methods

4

1 回答 1

8

首先,这种行为和背后的推理一直存在;这对 1.9 来说并不是什么新鲜事。它发生的技术原因是因为它main是特殊的并且与任何其他对象都不同。没有花哨的解释:它的行为方式是因为它是这样设计的。

好吧,但是为什么?main神奇的理由是什么?因为 Ruby 的设计师 Yukihiro Matsumoto 认为拥有这种行为会使语言变得更好:

是这样,为什么顶级方法没有在这个对象上创建单例方法,而不是作为对象类本身的实例方法被拉入(因此进入所有其他类,即比通常预期的更多的命名空间污染)。这仍然允许顶级方法调用其他顶级方法。如果顶层对象被某个常量(如 Main)引用,那么可以使用 Main.method(...) 从任何地方调用这些方法。

您真的希望在任何地方都输入“Main.print”吗?

在进一步的讨论中,他解释说它的行为方式是因为他觉得“假设是自然的”。

编辑:

针对您的评论,您的问题是针对为什么 main 的 eigenclass 似乎报告hello为私有实例方法。问题是没有一个顶级函数实际上被添加到main,而是直接添加到Object. 当使用特征类时,instance_methods函数族总是表现得好像特征类仍然是原始类。也就是说,在类中定义的方法被视为直接在特征类中定义。例如:

class Object
  private
  def foo
    "foo"
  end
end

self.send :foo  # => "foo"
Object.private_instance_methods(false).include? :foo  # => true
self.meta.private_instance_methods(false).include? :foo  # => true

class Bar
  private
  def bar
    "bar"
  end
end

bar = Bar.new
bar.send :bar  # => "bar"
Bar.private_instance_methods(false).include? :bar  # => true
bar.meta.private_instance_methods(false).include? :bar  # => true

不过,我们可以直接向main的 eigenclass 添加一个方法。将您的原始示例与此进行比较:

def self.hello; "hello world"; end

Object.instance_methods.include? :hello  # => false
self.meta.instance_methods.include? :hello  # => true

好的,但是如果我们真的想知道给定函数是在 eigenclass 上定义的,而不是在原始类上定义的呢?

def foo; "foo"; end  #Remember, this defines it in Object, not on main
def self.bar; "bar"; end  #This is defined on main, not Object

foo  # => "foo"
bar  # => "bar"

self.singleton_methods.include? :foo  # => false
self.singleton_methods.include? :bar  # => true
于 2009-11-19T19:59:13.940 回答