puts
方法是Kernel
模块的单例方法。通常情况下,当一个模块被其他模块
include
或extend
时,该模块(但不包括其单例类)会被添加到继承树中。这样实际上将该模块的实例方法可用于该模块或它的单例类(对于include
和extend
分别处理)......但混合模块的单例方法仍然无法访问,因为模块的单例类从未被添加到继承树中。那么我为什么能使用
puts
(以及其他Kernel单例方法)?Kernel.singleton_methods(false)
# => [:caller_locations, :local_variables, :require, :require_relative, :autoload, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :test, :warn, :autoload?, :fork, :binding, :exit, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :URI, :eval, :iterator?, :block_given?, :catch, :throw, :loop, :gets, :sleep, :proc, :lambda, :trace_var, :untrace_var, :at_exit, :load, :Rational, :select, :Complex, :syscall, :open, :printf, :print, :putc, :puts, :readline, :readlines, :`, :p, :system, :spawn, :exec, :exit!, :abort, :set_trace_func, :rand, :srand, :trap, :caller]
请注意,
puts
似乎不是Kernel
上的实例方法:
Kernel.instance_methods.grep(/puts/)
# []
虽然 Object
包括 Kernel
Object.included_modules
# [Kernel]
据我所知,
Kernel
的单例类 (#<Class:Kernel>
) 没有出现在任何对象的祖先链中。 is_a?
也没有显示包含它:Object.is_a? Class.singleton_class # false
Object.is_a? Kernel.singleton_class # false
Object.singleton_class.is_a? Class.singleton_class # true
Object.singleton_class.is_a? Kernel.singleton_class # false
然而,由于某种原因,它们对于每个对象都显示为私有方法。
Object.puts "asdf"
# NoMethodError (private method `puts' called for Object:Class)
如果
#<Class:Kernel>
在祖先链中没有显示,那么方法查找如何找到这些方法呢?相关内容:
- Ruby对象的方法查找路径
- 类、模块、它们的特殊类和方法查找
- 注意:这与我的问题不同,因为这是类继承,所以
#<Class:Class>
继承自#<Class:Module>
- 注意:这与我的问题不同,因为这是类继承,所以
- 为什么一个模块的单例方法在混入后面向下的特殊类中不可见?
Object
包括Kernel
模块,但puts
等方法不是Kernel
上的方法 - 它们是Kernel
的单例类上的方法,因此不应该对Object
可用。 - rintaunmodule M; def self.m; end end
Object.include M
Object.included_modules # => [M, Kernel]
Object.m # NoMethodError (undefined method 'm' for Object:Class)
- rintaunKernel
的工作方式如下:module M; private; def m; end; end; Object.include M
- steenslag#instance_methods
不包括私有方法。我之前没有意识到这一点。Kernel.private_instance_methods
确实包括#puts
和其他私有方法。如果你更新你的回答并解释清楚,我会接受它的。谢谢! - rintaun