ruby的include和extend prepend
Ruby中module的功能很像Java中的接口,在module中定义可以在多个类中复用的方法,然后在各个类中“引入”这个module,类或者类的实例就可以访问到module中定义的方法。
如何在类中“引入”module?Ruby提供了3个关键字: include, extend和prepend。
include
直接看例子:
# 定义module module IndoorPet def can_be_housebroken? true end end # 定义需要引入module的类 class Animal end class Dog < Animal include IndoorPet end class Cat < Animal include IndoorPet end class Rabbit < Animal include InddorPet end roger = Rabbit.new("Roger") roger.can_be_housebroken? # 返回true Rabbit.can_be_housebroken? # 抛异常 NoMethorError: undefined method 'can_be_housebroken?' for Rabbit::Class 复制代码
可以看到,通过include引入的module,module中定义的方法会作为实例方法引入,也就是类的实例可以调用,而类不可以直接调用。
通过ancestors方法打印类的祖先链:
Rabbit.ancestors # 返回 [Rabbit, IndoorPet, Animal, Object, PP::ObjectMixin, Kernel, BasicObject] 复制代码
可以看到,在Rabbit的祖先链上,IndoorPet位于Rabbit 与它的superclass之间。
extend
直接看例子:
# 省略IndoorPet的定义 class Animal end class Dog < Animal extend IndoorPet end class Cat < Animal extend IndoorPet end class Rabbit < Animal extend IndoorPet end roger = Rabbit.new("Roger") roger.can_be_housebroken? # 抛异常 NoMethodError: undefined method `can_be_housebroken?' for #<Rabbit:0x00007fa84389c748> Rabbit.can_be_housebroken? # 返回 true 复制代码
可以看到,通过extend引入的module,module中定义的方法会作为类方法引入,也就是类可以调用,但是类的实例不可调用。
通过ancestors方法打印类的祖先链:
Rabbit.ancestors # 返回 [Rabbit, Animal, Object, PP::ObjectMixin, Kernel, BasicObject] 复制代码
可以看到,通过extend方式引入的module,并不在Rabbit的祖先链上。
prepend
直接看例子:
class Animal end class Dog < Animal prepend IndoorPet end class Cat < Animal prepend IndoorPet end class Rabbit < Animal prepend IndoorPet end roger = Rabbit.new("Roger") roger.can_be_housebroken? # 返回 true Rabbit.can_be_housebroken? # 抛出 NoMethodError: undefined method `can_be_housebroken?' for Rabbit:Class 复制代码
可以看到,通过prepend引入的module,module中的方法和include方式类似,也是作为类的实例方法引入的。
但是,通过ancestors方法打印类的祖先链的话,结果与include不同:
Rabbit.ancestors # 返回 [IndoorPet, Rabbit, Animal, Object, PP::ObjectMixin, Kernel, BasicObject] 复制代码
IndoorPet位于祖先链的最低部。
结论
通过上述三种方式引入module的话:
- include:将module中的方法作为实例方法引入,而非类方法;同时,module位于祖先连上的Class与Superclass之间。
- extend:将module中的类作为类方法引入,而非实例方法;同时,module不会在祖先链上出现。
- prepend:将module中的方法作为实例方法引入,而非类方法;同时,module位于祖先连上的最底部。
Reference
作者:danielkoo
链接:https://juejin.cn/post/7187791611042988090
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://juejin.cn/post/7187791611042988090
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
阅读量: 691
发布于:
修改于:
发布于:
修改于: