What is the difference between include and extend in Ruby?
只是想了解一下Ruby元编程。混音/模块总是让我困惑。
- 包括:将指定的模块方法混合为目标类中的实例方法
- 扩展:将指定的模块方法混合为目标类中的类方法
- 如果您调用
Klazz.extend(Mod) ,现在klazz有mod的方法(作为类方法) - 如果您调用
obj.extend(Mod) ,现在obj有mod的方法(作为实例方法),但是没有其他obj.class 的实例添加这些方法。 extend 是一种公共方法。- 如果调用
class Klazz; include Mod; end; ,那么现在klazz的所有实例都可以访问mod的方法(作为实例方法) include 是一个私有方法,因为它是从容器类/模块内部调用的。- 如果mod已经包含在klazz或它的祖先中,那么include语句将不起作用。
- 它还包括了国防部在克拉兹的常量,只要它们不冲突
- 它允许Klazz访问mod的模块变量,例如
@@foo 或@@bar 。 - 如果存在循环包含,则引发ArgumentError
- 将模块作为调用方的直接祖先(即,它将mod添加到klazz.precements,但mod不添加到klazz.superclass.superclass.superclass的链中。因此,在Klazz Foo中调用
super 将检查mod Foo,然后检查Klazz真正的超类的Foo方法。详情见Rubyspec)。 #include Rubyspec RubyDoc公司#included Rubyspec RubyDoc公司#extend Rubyspec RubyDoc公司#extended Rubyspec RubyDoc公司#extend_object Rubyspec RubyDoc公司#append_features Rubyspec RubyDoc公司
小精灵
那么主要的区别是这一点还是一条更大的龙潜伏着呢?例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | module ReusableModule def module_method puts"Module Method: Hi there!" end end class ClassThatIncludes include ReusableModule end class ClassThatExtends extend ReusableModule end puts"Include" ClassThatIncludes.new.module_method #"Module Method: Hi there!" puts"Extend" ClassThatExtends.module_method #"Module Method: Hi there!" |
extend-将指定模块的方法和常量添加到目标的元类(即singleton类)中。例如
小精灵
include-默认情况下,它将指定模块的方法混合为目标模块/类中的实例方法。例如
小精灵
然而,模块经常通过猴子修补
更多关于
1 2 3 | class Klazz include Mod end |
小精灵
当然,Ruby核心文档始终是处理这些问题的最佳位置。Rubyspec项目也是一个很棒的资源,因为它们精确地记录了功能。
小精灵
你说的是对的。然而,还有更多的事情要做。
如果您有一个类
没错。
在幕后,include实际上是附加功能的别名,它(来自文档):
Ruby's default implementation is to
add the constants, methods, and module
variables of this module to aModule if
this module has not already been added
to aModule or one of its ancestors.
号
所有其他答案都很好,包括挖掘rubyspecs的提示:
https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb
https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb
至于用例:
如果在包含的类类类中包含模块可重用模块,则将引用方法、常量、类、子模块和其他声明。
如果扩展使用模块可重用模块扩展的类类,那么方法和常量将被复制。显然,如果不小心,您可以通过动态复制定义来浪费大量内存。
如果使用activesupport::concern,.included()功能可以直接重写include类。关注点内的模块类方法被扩展(复制)到include类中。
我还想解释一下这个机制的工作原理。如果我不对,请纠正。
当我们使用
1 2 3 4 5 6 | class A include MyMOd end a = A.new a.some_method |
对象没有方法,只有类和模块有。因此,当
当我们使用
因此,
此外,还有一个预发送方法,用于更改查找路径:
A=>A'=>预装模块至A=>A=>包含模块至A
抱歉我英语不好。