2012-07-18 30 views
39

在ruby中,我明白模塊函數可以在模塊中使用module_function而不需要混合,如下所示。我可以看到這是如何有用的,所以你可以使用該功能,而不需要在模塊中混合。ruby​​ module_function vs including模塊

module MyModule 
    def do_something 
    puts "hello world" 
    end 
    module_function :do_something 
end 

我的問題是,爲什麼你可能想要定義這兩種方法的函數。

爲什麼不只是有

def MyModule.do_something 

OR

def do_something 

在什麼樣的情況下將有可進行混合的功能,或用作靜態方法它是有用的?

回答

35

想到Enumerable

這是您需要將其包含在模塊中的完美示例。如果你的班級定義了#each,那麼只需加入一個模塊(#map#select等)即可獲得很多好處。當我使用模塊作爲mixin時,這是唯一的情況 - 當模塊提供了幾個方法的功能時,在包含模塊的類中定義它。我可以爭辯說,這應該是一般情況下唯一的情況。

至於界定「靜態」的方法,更好的方法是:

module MyModule 
    def self.do_something 
    end 
end 

你並不真的需要調用#module_function。我認爲這只是奇怪的遺留問題。

你甚至可以做到這一點:

module MyModule 
    extend self 

    def do_something 
    end 
end 

...但它不會很好地工作,如果你還希望包括模塊的某個地方。我建議避免它,直到你瞭解Ruby元編程的細微之處。

最後,如果你只是做:

def do_something 
end 

...它不會最終作爲一個全球性的功能,但作爲Object私有方法(有沒有功能在Ruby中,只是方法)。有兩個缺點。首先,你沒有命名空間 - 如果你定義了另一個具有相同名稱的函數,那麼你將會在稍後得到一個函數。其次,如果您的功能按照#method_missing執行,則在Object中使用私有方法會影響它。最後,猴子修補Object只是邪惡的業務:)

編輯:

module_function可以在類似於private的方式來使用:

module Something 
    def foo 
    puts 'foo' 
    end 

    module_function 

    def bar 
    puts 'bar' 
    end 
end 

這樣的話,你可以打電話Something.bar,但不不是Something.foo。如果在此調用module_function後定義了任何其他方法,它們也可在未混合的情況下使用。

雖然我不喜歡它,但有兩個原因。首先,混入並具有「靜態」方法的模塊聽起來有點不妥。可能有些有效的情況,但不會經常發生。正如我所說的,我更喜歡將模塊用作名稱空間或混合使用,但不是兩者兼而有之。

其次,在本示例中,bar也可用於在Something中混合的類/模塊。我不知道什麼時候這是可取的,因爲任何方法使用self,它必須混入或不混入,然後它不需要混入。

我認爲使用module_function沒有通過該方法的名稱比使用更經常使用。 privateprotected也一樣。

+0

感謝您的解釋。我明白你爲什麼要混入一個模塊,我的問題更多的是關於什麼時候可以使用module_function。你有沒有什麼時間可以使用它? – 2012-07-19 00:40:36

+2

這個最後一個例子中有'module_function'的另外一個例子:'private'函數'foo'不能從'bar'裏面訪問,因爲'foo'是一個實例方法(它沒有'self') ,只有當這個模塊在某個類中混合時纔可以調用它。當它是一個僅用於命名空間目的的獨立模塊時是不可能的。那麼如何擁有它呢?如何將模塊用於名稱空間並隱藏來自外部世界的一些實現助手函數,但允許它們通過其接口方法調用? – SasQ 2013-09-03 06:10:15

12

這是Ruby庫提供不使用(很多)內部狀態的功能的好方法。因此,如果您(例如)想要提供sin函數並且不想污染「全局」(Object)名稱空間,則可以將其定義爲常量下的類方法(Math)。

但是,想要編寫數學應用程序的應用程序開發人員每兩行可能需要sin。如果該方法也是實例方法,她可以包含Math(或My::Awesome::Nested::Library)模塊,現在可以直接調用sin(stdlib示例)。

這實際上是讓圖書館對用戶更舒適。如果他們希望圖書館的功能處於頂級水平,他們可以自己選擇。

順便說一句,您可以通過使用:extend self(在模塊的第一行)實現類似的功能,如module_function。在我看來,它看起來更好,讓事情變得更清晰。

更新:更多背景資料在this blog article

+3

[ruby styleguide](https://github.com/bbatsov/ruby-style-guide#classes--modules)比''extend self''優先''module_function''' – zhon 2013-12-07 17:12:51

+3

感謝您的指針。不過,我不同意。 'module_function'可能對初學者更友好,但是每個認真對待Ruby的人都應該能夠閱讀和理解'extend self'版本。 「擴展自我」不是抽象的。它使用Ruby的基本工具集,而'module_function'可以從Ruby中刪除,而不會丟失重要的功能。 – 2013-12-07 18:09:13

+0

謝謝你給你的理由。在閱讀本Q/A之前,我使用了'self.method''和''class << self''。 – zhon 2013-12-07 19:43:59