Jef*_*rey 48 ruby module mixins
在ruby中,我知道模块功能可以通过使用module_function
如此处所示而无需在模块中混合而可用.我可以看到它是如何有用的,因此您可以在模块中使用该功能而无需混合.
module MyModule
def do_something
puts "hello world"
end
module_function :do_something
end
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么你可能希望这两种方式定义函数.
为什么不呢
def MyModule.do_something
Run Code Online (Sandbox Code Playgroud)
要么
def do_something
Run Code Online (Sandbox Code Playgroud)
在哪种情况下,将函数混合使用或用作静态方法是有用的?
Ste*_*nev 43
想想可数.
这是您需要将其包含在模块中的完美示例.如果你的类定义#each
,你只需通过包括模块(得到了很多善良的#map
,#select
等等).这是我使用模块作为mixins的唯一情况 - 当模块根据几个方法提供功能时,在类中定义了包含模块的模块.我可以说这应该是一般的唯一案例.
至于定义"静态"方法,更好的方法是:
module MyModule
def self.do_something
end
end
Run Code Online (Sandbox Code Playgroud)
你真的不需要打电话#module_function
.我认为这只是奇怪的传统内容.
你甚至可以这样做:
module MyModule
extend self
def do_something
end
end
Run Code Online (Sandbox Code Playgroud)
...但如果您还想将模块包含在某处,它将无法正常工作.我建议在学习Ruby元编程的细微之处之前避免使用它.
最后,如果您这样做:
def do_something
end
Run Code Online (Sandbox Code Playgroud)
...它不会最终成为一个全局函数,而是作为一个私有方法Object
(Ruby中没有函数,只是方法).有两个缺点.首先,你没有命名空间 - 如果你定义了另一个具有相同名称的函数,那么它就是你以后得到的那个.其次,如果你有实现的功能#method_missing
,有一个私有方法Object
将影子它.最后,猴子修补Object
只是邪恶的事业:)
编辑:
module_function
可以类似于以下方式使用private
:
module Something
def foo
puts 'foo'
end
module_function
def bar
puts 'bar'
end
end
Run Code Online (Sandbox Code Playgroud)
那样,你可以打电话Something.bar
,但不是Something.foo
.如果在此调用之后定义任何其他方法module_function
,它们也可以在不混合的情况下使用.
不过,我不喜欢它有两个原因.首先,混合在一起并具有"静态"方法的模块听起来有点狡猾.可能存在有效案例,但不会那么频繁.正如我所说,我更喜欢将模块用作命名空间或将其混合使用,但不是两者兼而有之.
其次,在这个例子中,bar
混合的类/模块也可以使用Something
.我不确定何时这是可取的,因为该方法使用self
并且必须混合,或者不混合,然后它不需要混合.
我认为使用module_function
而不传递方法的名称比使用更频繁.这同样适用于private
和protected
.
J-_*_*_-L 15
这是Ruby库提供不使用(很多)内部状态的功能的好方法.因此,如果您(例如)想要提供sin
函数并且不想污染"global"(Object
)命名空间,则可以在constant(Math
)下将其定义为类方法.
但是,想要编写数学应用程序的应用程序开发人员可能需要sin
每两行.如果该方法也是一个实例方法,她可以只包含Math
(或My::Awesome::Nested::Library
)模块,现在可以直接调用sin
(stdlib示例).
这真的是为了让图书馆的用户更舒适.如果他们希望您的图书馆的功能在顶层,他们可以选择自己.
顺便说一句,您可以实现类似的功能,例如module_function
:使用:( extend self
在模块的第一行).在我看来,它看起来更好,让事情更清楚一点.
更新:此博客文章中的更多背景信息.