假设我想用我刚刚提出的一种方法修补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 << Object
def say_hello
puts "hello world"
end
end
将say_hello
存储在Object
的单例类中会允许我们将其用作类方法,而只是Kernel
中包含Object
而不应该包含g
#39; t允许这种行为。但确实如此。有人知道为什么?
由于
答案 0 :(得分:5)
中
Kernel
仅包含在Object
[...]
这是正确的。
[...]不应该允许这种行为。
你忽略了类也是对象。
如果say_hello
是obj
的一个实例,让我们看看Object
方法的来源:
obj = Object.new
obj.method(:say_hello)
#=> #<Method: Object(Kernel)#say_hello>
正如预期的那样。 obj
是Object
的实例,Object
包含Kernel
:
obj.class.include? Kernel
#=> true
obj.class.ancestors
#=> [Object, Kernel, BasicObject]
现在让我们看看如果obj
是类Object
会发生什么:
obj = Object
obj.method(:say_hello)
#=> #<Method: Class(Kernel)#say_hello>
此时obj
是Class
的实例,Class
还包含Kernel
:
obj.class.include? Kernel
#=> true
obj.class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]
Ruby的documentation注意到类方法实际上只是在类对象上定义的实例方法:(强调添加)
class C def self.my_method # ... end end
然而,这只是Ruby中更强大的语法能力的一种特殊情况,即向任何对象添加方法的能力。类是对象,因此添加类方法只是向Class对象添加方法。