红宝石顶层定义的方法在哪里?

hor*_*guy 7 ruby singleton metaclass ruby-1.9

在顶层,方法定义应该导致私有方法开启Object,测试似乎证实了这一点:

def hello; "hello world"; end

Object.private_instance_methods.include?(:hello) #=> true
Object.new.send(:hello) #=> "hello world"
Run Code Online (Sandbox Code Playgroud)

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

self.meta.private_instance_methods(false).include?(:hello) #=> true
Run Code Online (Sandbox Code Playgroud)

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

Pes*_*sto 8

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

好的,但为什么呢?什么main是神奇的理由?因为Ruby的设计师Yukihiro Matsumoto认为它使语言更好地具有这种行为:

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

你真的希望到处输入"Main.print"吗?

在讨论中,他解释说它表现得这样,因为他觉得"假设是自然的".

编辑:

在回答您的评论时,您的问题是针对为什么main的本征类似乎报告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
Run Code Online (Sandbox Code Playgroud)

不过,我们可以直接将方法添加到本main征类中.将您的原始示例与此进行比较:

def self.hello; "hello world"; end

Object.instance_methods.include? :hello  # => false
self.meta.instance_methods.include? :hello  # => true
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)