Ruby Mixin调用报错:NoMethodError: undefined method `meow?' for #<实例>
解决Ruby Mixin中NoMethodError的问题
看起来你是把模块里的方法类型搞混啦!Ruby的Mixin机制是把模块的实例方法混入到目标类的实例方法集合里的,如果你的模块里定义的是模块自身的类方法(带self.前缀),那就算类include了模块,实例也调用不了这个方法,这就是你遇到NoMethodError的核心原因。
先看你可能写错的代码示例
比如你可能写出了这样的代码:
module Cats # 这是模块Cats的类方法,不是实例方法 def self.meow? true end end class Animal # 虽然include了模块,但模块里没有实例方法可以混入 include Cats end e = Animal.new e.meow? # 这里必然报错:NoMethodError: undefined method 'meow?' for #<Animal:0x00000001050a21d0>
正确的写法(让实例能调用meow?)
要让实例e能调用meow?,同时和Cats.meow?结果一致,有两种常见方案:
方案1:把模块的方法改成实例方法,直接混入
如果不需要单独调用Cats.meow?,可以直接把模块里的方法定义为实例方法:
module Cats # 这是模块的实例方法,会被混入到类的实例方法中 def meow? true end end class Animal include Cats end e = Animal.new puts e.meow? # 输出 true
方案2:保留模块的类方法,同时定义实例方法调用它
如果你需要同时保留Cats.meow?的调用能力,又想让实例能调用,可以在模块里加一个实例方法,内部调用模块的类方法:
module Cats # 模块的类方法 def self.meow? true end # 模块的实例方法,混入后实例可以调用 def meow? Cats.meow? end end class Animal include Cats end e = Animal.new puts e.meow? # 输出 true,和Cats.meow?结果一致 puts Cats.meow? # 同样输出 true
核心原理回顾
Ruby的Mixin通过include关键字,把模块里的实例方法添加到目标类的实例方法查找路径中。而用self.定义的方法是模块本身的类方法,不属于实例方法范畴,所以不会被混入。如果是想给类添加类方法,可以用extend关键字,但那是给类本身添加方法,实例依然调用不了。
内容的提问来源于stack exchange,提问作者Daniel Grimes
相关产品推荐
相关产品推荐

