kst*_*tis 3 ruby metaprogramming object-model
假设我想Kernel用一个我想出的方法修补模块:
module Kernel
def say_hello
puts "hello world"
end
end
Run Code Online (Sandbox Code Playgroud)
我现在可以做到这一点:
Object.new.say_hello # => hello world
Run Code Online (Sandbox Code Playgroud)
但我也可以做以下通常不应该做的事情:
Object.say_hello # => hello world
Run Code Online (Sandbox Code Playgroud)
由于Object包含Kernel它的实例方法,因此所有Object实例都应该响应say_hello.到现在为止还挺好.
然而,Object.say_hello似乎是一种类方法,只有在我们做了类似的事情时才能证明:
class << Object
def say_hello
puts "hello world"
end
end
Run Code Online (Sandbox Code Playgroud)
存储say_hello在Object单例类中将允许我们将它用作类方法,而Kernel只是包含在Object其中,不应该允许这种行为.但确实如此.有人知道为什么?
谢谢
Kernel仅包括在Object[...]
那是正确的.
[...]不应该允许这种行为.
你忽略了类也是对象.
say_hello如果obj是以下实例,让我们看看方法的来源Object:
obj = Object.new
obj.method(:say_hello)
#=> #<Method: Object(Kernel)#say_hello>
Run Code Online (Sandbox Code Playgroud)
正如预期的那样.obj是的一个实例Object和Object包括Kernel:
obj.class.include? Kernel
#=> true
obj.class.ancestors
#=> [Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)
现在让我们看看如果obj是类会发生什么Object:
obj = Object
obj.method(:say_hello)
#=> #<Method: Class(Kernel)#say_hello>
Run Code Online (Sandbox Code Playgroud)
这一次,obj是一个实例Class,并Class还包括Kernel:
obj.class.include? Kernel
#=> true
obj.class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)
Ruby的文档指出,类方法实际上只是在类对象上定义的实例方法:(强调添加)
Run Code Online (Sandbox Code Playgroud)class C def self.my_method # ... end end但是,这只是Ruby中具有更强语法能力的特殊情况,即向任何对象添加方法的能力.类是对象,因此添加类方法只是向Class对象添加方法.