rubymodule_function与包括模块
在ruby中,我明白模块的function可以通过使用module_function
在模块中混合使用,如下所示。 我可以看到这是如何有用,所以你可以使用该function,而不需要在模块中混合。
module MyModule def do_something puts "hello world" end module_function :do_something end
我的问题是,为什么你可能想要定义这两种方式的function。
为什么不只是有
def MyModule.do_something
要么
def do_something
在什么样的情况下将这个function混合在一起,或者作为一个静态的方法来使用呢?
想想Enumerable 。
这是您需要将其包含在模块中的最佳示例。 如果你的类定义了#each
,那么只要包含一个模块( #map
, #select
等)就可以得到很多好处。 当我使用模块作为mixin时,这是唯一的情况 – 当模块提供了几个方法的function时,在包含模块的类中定义它。 我可以说,这应该是一般情况下唯一的情况。
至于定义“静态”方法,更好的方法是:
module MyModule def self.do_something end end
你并不需要调用#module_function
。 我认为这只是古怪的东西。
你甚至可以这样做:
module MyModule extend self def do_something end end
…但是如果你也想在某个地方join这个模块的话,它将不能很好地工作。 我build议避免它,直到你了解Ruby元编程的微妙之处。
最后,如果你只是这样做:
def do_something end
…它不会以全局函数结束,而是作为Object
上的私有方法(Ruby中没有函数,只是方法)。 有两个缺点。 首先,你没有命名空间 – 如果你定义了另外一个同名的函数,那么你将得到一个函数。 其次,如果你#method_missing
实现的function,在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
而不传递方法的名称比使用相当频繁。 同样的private
和protected
。
这是Ruby库提供不使用(很多)内部状态的function的好方法。 所以如果你想提供一个sin
函数而不想污染“global”( Object
)命名空间,你可以在常量( Math
)下定义它作为类方法。
但是,想要编写math应用程序的应用程序开发人员可能需要每两行一行。 如果方法也是一个实例方法,她可以包含Math
(或My::Awesome::Nested::Library
)模块,现在可以直接调用sin
(stdlib示例)。
这实际上是让一个图书馆更加舒适的用户。 他们可以自己select,如果他们希望你的图书馆的function在顶层。
顺便说一下,通过使用: extend self
(在模块的第一行),可以实现类似于module_function
的function。 在我看来,它看起来更好,让事情变得更清楚。
更新: 本博客文章中的更多背景信息。
如果你想看一个工作的例子,看看慢性gem:
https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb
和Handlers被包含在这里的Parser类中:
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
他使用module_function将处理程序的方法发送到使用该实例的invoke方法的Handler的特定实例。