ruby中的include, extend, prepend.
在讲解这关键词之前,先要了解ruby中的Module的概念。ruby是面向对象语言,而类(class)是面向对象语言中一个非常重要的概念,一个类往往映射一个主体(entity). 类具有的属性和行为我们可以通过getter,setter,method的方式写到一个类文件中,但是随着单文件代码的增多,将变得不可维护,这就需要通过其它方式来根据作用的不同,来管理不同模块的代码,所以ruby中引入了module的概念。
声明一个module
module A
end
那module怎么被class引用呢? ruby中有一个概念叫mixin,也就是将module里方法mixin到class里。
include方法
我们使用include实现个简单的例子:
module Nameable
def hi
"Hi, I am From Nameable module"
end
end
class U
include Nameable
end
u = U.new
u.hi
#=> "Hi, I am From Nameable module"
上面在U类中通过include将Nameable mixin了进来后,U的实例便可以通过类似实例方法的调用方式来调用hi方法。
extend方法
接下来使用extend实现一下:
module Nameable
def hi
"Hi, I am From Nameable module"
end
end
class U
extend Nameable
end
u = U.new
u.hi
#=> undefined method `hi' for #<U:0x007fbac31470f0>
U.hi
#=> "Hi, I am From Nameable module"
上面在U类中通过extend将Nameable mixin了进来后,U便可以通过类似类方法的调用方式来调用hi方法。
以上也是include和extend的主要区别,可以理解为include将module中的方法作为实例方法mixin进来,而extend将将module中的方法作为类方法mixin进来。
方法查找
那如果mixin过来的module和类自身有同名的方法,ruby会怎么做呢,再做一个实验.
module Nameable
def hi
"Hi, I am From Nameable module"
end
end
class U
include Nameable
def hi
"Hi, I am From U class"
end
end
u = U.new
u.hi
#=> "Hi, I am From U class"
这表示,U实例再查找hi方法时,会优先在类文件里查找,如果找到hi方法,便不再继续查找,所以没有去查找module里的hi方法,这个在ruby中叫做。
再看一下稍微复杂点的例子:
module Nameable
def hi
"Hi, I am From Nameable module"
end
end
class U
def hi
"Hi, I am From U class"
end
end
class U1 < U
include Nameable
end
u1 = U1.new
u1.hi
#=> "Hi, I am From Nameable module"
上面代码中U1继承了U类,在U1的实例调用hi方法时,在方法查找链上,会先在U1类文件中查找,接着在minxin进来的Nameable里查找,然后在U类中查找。这里在Nameable里查找成功后结束查找。 我们看一下U1类的祖先链, 便可清晰的看出方法查找链:
U1.ancestors
#=> [U1, Nameable, U, Object, Kernel, BasicObject]
prepend方法
根据上面的例子我们知道,ruby中的方法查找,是先从自身类中查找,然后从mixin或者继承的父类中查找。那如果想优先用mixin module中的方法怎么做呢,这就引出了prepend方法。还是上面最简单的例子:
module Nameable
def hi
"Hi, I am From Nameable module"
end
end
class U
prepend Nameable
def hi
"Hi, I am From U class"
end
end
u = U.new
u.hi
#=> "Hi, I am From Nameable module"
上面prepend将Nameable里的hi方法优先加载进来供U实例查找,而不再调用该类中定义的hi方法。另外prepend和include一样的地方是mixin进来的方法作为实例方法使用。
super关键词
谈到方法查找就不得不涉及ruby中的super关键词。super用来调用父类中的同名方法.
class Animal
def name
"Animal"
end
end
class Cat < Animal
def name
"The Cat is an #{super}"
end
end
Cat.new.name
#=> "The Cat is an Animal"
这样Cat的实例在调用super时,会向上查找父类的同名name方法并调用.
注意: super和super()的要根据父类中方法是否需要传参区分使用。
参考: https://dev.to/d4vsanchez/my-journey-into-ruby-modules-8il
https://www.rubyguides.com/2018/09/ruby-super-keyword/