剛剛開始關注Ruby元編程。 mixin / modules老是讓我困惑。 html
那麼主要區別在於這仍是潛伏着更大的龍? 例如 git
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!"
那是對的。 github
在幕後,include其實是append_features的別名,(來自文檔): 編程
Ruby的默認實現是將此模塊的常量,方法和模塊變量添加到aModule(若是此模塊還沒有添加到aModule或其祖先之一)。 ruby
你所說的是對的。 然而,除此以外還有更多。 app
若是你有一個類Klazz
和模塊Mod
,包括Klazz
Mod
, Klazz
讓Klazz
訪問Mod
的方法。 或者您可使用Mod
擴展Klazz
,使Klazz
類 Klazz
訪問Mod
的方法。 可是你也能夠用o.extend Mod
擴展一個任意對象。 在這種狀況下,單個對象獲取Mod
的方法,即便與o
具備相同類的全部其餘對象也沒有。 spa
我還想解釋它的做用機制。 若是我不對,請糾正。 .net
當咱們使用include
咱們將從類中添加一個連接到一個包含一些方法的模塊。 code
class A include MyMOd end a = A.new a.some_method
對象沒有方法,只有clases和模塊。 因此當a
接收消息some_method
它開始在a
特徵類中搜索方法some_method
,而後在A
類中而後連接到A
類模塊,若是有一些(以相反順序,最後包括勝利)。 htm
當咱們使用extend
咱們將對象的特徵類中的模塊添加連接。 所以,若是咱們使用A.new.extend(MyMod),咱們將模塊的連接添加到A的實例特徵類或a'
類。 若是咱們使用A.extend(MyMod),咱們將添加連接到A(對象,類也是對象)本徵類A'
。
所以對於方法查找路徑a
是以下:a =>一個「=>連接的模塊爲」類=> A.
還有一個更改查找路徑的prepend方法:
a => a'=>前置模塊A => A =>包含模塊到A
對不起,個人英語很差。
extend - 將指定模塊的方法和常量添加到目標的元類(即單例類),例如
Klazz.extend(Mod)
,如今Klazz有Mod的方法(做爲類方法) obj.extend(Mod)
,如今obj有Mod的方法(做爲實例方法),但沒有其餘obj.class
實例添加了這些方法。 extend
是一種公共方法 include - 默認狀況下,它將指定模塊的方法混合爲目標模塊/類中的實例方法。 例如
class Klazz; include Mod; end;
class Klazz; include Mod; end;
,如今Klazz的全部實例均可以訪問Mod的方法(做爲實例方法) include
是一個私有方法,由於它是從容器類/模塊中調用的。 可是 ,模塊常常經過猴子修補included
方法來覆蓋 include
的行爲。 這在傳統的Rails代碼中很是突出。 來自Yehuda Katz的更多細節 。
假設您運行如下代碼,有關include
其默認行爲的更多詳細信息
class Klazz include Mod end
@@foo
或@@bar
super
將檢查Mod#foo以前檢查Klazz真正的超類的foo方法。有關詳細信息,請參閱RubySpec。)。 固然, ruby核心文檔老是最適合這些事情的地方。 RubySpec項目也是一個很棒的資源,由於他們精確地記錄了這些功能。
#include
RubySpec rubydoc #included
RubySpec rubydoc #extend
RubySpec rubydoc #extended
RubySpec rubydoc #extend_object
RubySpec rubydoc #append_features
RubySpec rubydoc 全部其餘答案都很好,包括挖掘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
至於用例:
若是在ClassThatIncludes類中包含模塊ReusableModule,則會引用方法,常量,類,子模塊和其餘聲明。
若是使用模塊ReusableModule 擴展類ClassThatExtends,則會複製方法和常量。 顯然,若是你不當心,你能夠經過動態複製定義來浪費大量內存。
若是使用ActiveSupport :: Concern,則.included()功能容許您直接重寫包含類。 關注內的模塊ClassMethods被擴展 (複製)到包含類中。