Ruby 内核模块方法用作对象 class 方法

Ruby Kernel module methods used as Object class methods

假设我想用我刚刚想到的一种方法修补 Kernel 模块:

module Kernel
  def say_hello
    puts "hello world"
  end
end

我现在肯定能做到:

Object.new.say_hello # => hello world

但我还可以做以下我通常不应该做的事情:

Object.say_hello # => hello world

由于 Object 包含 Kernel 它采用其实例方法,因此所有 Object 实例都应响应 say_hello。到目前为止一切顺利。

然而 Object.say_hello 似乎是一种 class 方法,只有我们做了类似的事情才合理:

class << Object
  def say_hello
    puts "hello world"
  end  
end

Object 的单例 class 中存储 say_hello 将允许我们将其用作 class 方法,而不是 Kernel 仅包含在Object 不允许这种行为。但确实如此。有人知道为什么吗?

谢谢

Kernel is just included in Object [...]

没错。

[...] which shouldn't allow this behavior.

你忽略了 classes 也是对象。


如果objObject的实例,让我们看看say_hello方法来自哪里:

obj = Object.new

obj.method(:say_hello)
#=> #<Method: Object(Kernel)#say_hello>

果然不出所料。 objObject 的实例并且 Object 包括 Kernel:

obj.class.include? Kernel
#=> true

obj.class.ancestors
#=> [Object, Kernel, BasicObject]

现在让我们看看如果 obj 是 class Object:

会发生什么
obj = Object

obj.method(:say_hello)
#=> #<Method: Class(Kernel)#say_hello>

这次objClass的实例,Class还包括Kernel:

obj.class.include? Kernel
#=> true

obj.class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]

Ruby 的 documentation 指出 class 方法实际上只是在 class 对象上定义的实例方法:(强调)

class C
  def self.my_method
    # ...
  end
end

However, this is simply a special case of a greater syntactical power in Ruby, the ability to add methods to any object. Classes are objects, so adding class methods is simply adding methods to the Class object.