Ruby:两种给实例混入模块方法的方式是否等价?
为单个对象添加模块方法:两种实现是否等价?
问题背景
先定义模块与类:
module Dog def speak "woof" end end class Daschund; end
创建类的两个实例:
sausage = Daschund.new saveloy = Daschund.new
为单个实例添加Dog#speak实例方法有两种写法:
方式一:向对象元类include模块
class << sausage include Dog end
调用结果:
> sausage.speak => "woof"
方式二:调用object#extend
saveloy.extend Dog
调用结果:
> saveloy.speak => "woof"
问题核心:这两种方法是否等价?object#extend是否和将模块include到对象元类的操作完全一致?有没有验证方法?
结论:两者完全等价
Object#extend的本质就是将目标模块include到对象的**元类(singleton class)**中,以下是几种验证方式:
1. 对比元类的祖先链
通过查看对象元类的ancestors,可以看到模块的位置完全一致:
# 查看sausage的元类祖先 p class << sausage; ancestors; end # 输出示例:[#<Class:#<Daschund:0x00007f9b1a0a5d10>>, Dog, #<Class:Daschund>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] # 查看saveloy的元类祖先 p class << saveloy; ancestors; end # 输出示例:[#<Class:#<Daschund:0x00007f9b1a0a5cc0>>, Dog, #<Class:Daschund>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
Dog模块都被添加到了两个对象元类的直接祖先位置,方法查找顺序无差异。
2. 验证方法的归属
用method#owner查看方法所属模块,结果一致:
p sausage.method(:speak).owner # => Dog p saveloy.method(:speak).owner # => Dog
3. 验证模块修改的同步影响
修改Dog模块的方法后,两个对象的调用结果会同步更新,说明都是引用模块而非复制方法:
module Dog def speak "bow wow" end end p sausage.speak # => "bow wow" p saveloy.speak # => "bow wow"
内容的提问来源于stack exchange,提问作者user3574603
相关产品推荐
相关产品推荐

