Ruby反射:模块与类的成员信息查看方法问询
关于Ruby模块与反射的问题解答
问题1:任何模块都能作为类吗?
答案是否定的。在Ruby里,模块(Module)和类(Class)有明确区别:
- 类是
Class类的实例,而Class本身是Module的子类——简单说,类是特殊的模块,但模块不等于类。 - 模块无法直接实例化(不能用
new创建对象),也不能作为父类被其他类继承,它的核心作用是作为命名空间封装代码,或通过include/extend向类、对象注入方法。
你尝试puts BaseObject.class失败,是因为BaseObject这个常量在SonicPi环境中未定义,和模块能不能当类用无关。举个验证例子:
puts Gem.class # 输出 Module,说明Gem是Module类的实例 puts Class.superclass # 输出 Module,说明Class继承自Module
问题2:如何通过反射检查模块的相关信息?
由于SonicPi不支持RDoc,我们可以用Ruby内置的ObjectSpace和模块/类原生方法实现需求:
1. 获取当前环境中所有模块
通过ObjectSpace遍历所有Module实例,同时排除类(因为Class是Module的子类,会被一并遍历):
modules = ObjectSpace.each_object(Module).select { |mod| !mod.is_a?(Class) } modules.each { |mod| puts mod.name }
如果要包含类(毕竟类是特殊模块),直接去掉!mod.is_a?(Class)即可。
2. 获取某个模块内定义的类
通过模块的constants方法获取自身定义的常量,再筛选出Class类型的对象:
def classes_in_module(mod) # false 参数表示只获取模块自身定义的常量,不包含继承来的 mod.constants(false).map { |const_name| mod.const_get(const_name) }.select { |obj| obj.is_a?(Class) } end # 示例:查看Gem模块内的类 classes_in_module(Gem).each { |klass| puts klass.name }
3. 获取某个类的所有子类
Ruby 1.9+提供subclasses方法直接获取子类,若需要递归获取所有层级的子类,可写个简单递归方法:
def all_subclasses(klass) klass.subclasses + klass.subclasses.flat_map { |sub| all_subclasses(sub) } end # 示例:获取Object的所有子类 all_subclasses(Object).each { |sub| puts sub.name }
额外:查看模块独有的方法
你之前用my_object.methods - Object.instance_methods的思路可行,若要查看模块的类方法(单例方法),更直接的方式是用singleton_methods:
# 查看Gem模块独有的类方法 puts Gem.singleton_methods - Module.singleton_methods
若要查看模块的实例方法(include到类后会成为类实例方法的方法):
puts Gem.instance_methods - Object.instance_methods
内容的提问来源于stack exchange,提问作者Jonny Hotchkiss
相关产品推荐
相关产品推荐

