为什么我不能在Object的一个实例的单例类中包含Kernel

mko*_*mko 3 ruby metaprogramming

在顶级:

unbinded_method = method :puts

#=> Object(Kernel)#puts(*arg1)
Run Code Online (Sandbox Code Playgroud)

但我这样做了

obj = Object.new

obj.puts 'wow'
Run Code Online (Sandbox Code Playgroud)

我收到了一个未定义的错误

所以我假设内核模块没有包含在obj的单例类中,所以我做到了

obj.instance_eval do

include Kernel

end
Run Code Online (Sandbox Code Playgroud)

但我又得到了错误:

NoMethodError: undefined method `include' for #<Object:0x00000100b14dc8>
Run Code Online (Sandbox Code Playgroud)

Jör*_*tag 5

为什么我不能在Object的一个实例的单例类中包含Kernel

嗯,你可以:

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

class << obj
  include Kernel
end
obj.singleton_class.ancestors
# => [Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)

注:很明显,include荷兰国际集团Kernel为实例Object实际上并没有任何事情,因为Kernel已经在祖先链,并混入只能在祖先链出现一次.但如果你是include 另一个混合,那将是有效的:

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

class << obj
  include Enumerable
end
obj.singleton_class.ancestors
# => [Enumerable, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)

但我这样做了

obj = Object.new

obj.puts 'wow'
Run Code Online (Sandbox Code Playgroud)

我收到了一个未定义的错误

不,你没有.这是你得到的错误:

# NoMethodError: private method `puts' called for #<Object:0xdeadbed>
Run Code Online (Sandbox Code Playgroud)

它会告诉你那里的错误是什么问题:Kernel#puts是私有的,而在Ruby中,私有方法只能被调用为receiverless消息发送的结果.例如这样:

obj.instance_eval do puts 'wow' end
# wow
Run Code Online (Sandbox Code Playgroud)

要不就

obj.send :puts, 'wow' # send cirvumvents access protection
# wow
Run Code Online (Sandbox Code Playgroud)

所以我假设内核模块没有包含在obj的单例类中[...]

你为什么假设而不仅仅是检查?

obj.singleton_class.ancestors.include? Kernel # => true
Run Code Online (Sandbox Code Playgroud)

所以我做了

obj.instance_eval do
  include Kernel
end
Run Code Online (Sandbox Code Playgroud)

但我又得到了错误:

NoMethodError:未定义的方法`include'for#

同样,错误消息已经告诉您需要知道的所有内容:Object没有include方法,祖先链中也没有方法.include是一个Module类的方法,但是obj是一个Object,而不是一个Module.