ruby module_function vs 包含模块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11550213/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ruby module_function vs including module
提问by Jeff Storey
In ruby, I understand that module functions can be made available without mixing in the module by using module_functionas shown here. I can see how this is useful so you can use the function without mixing in the module.
在 ruby 中,我知道模块功能可以在不混合模块的情况下使用module_function,如下所示。我可以看到这是多么有用,因此您可以在不混入模块的情况下使用该功能。
module MyModule
def do_something
puts "hello world"
end
module_function :do_something
end
My question is though why you might want to have the function defined both of these ways.
我的问题是,为什么您可能希望以这两种方式定义函数。
Why not just have
为什么不只是拥有
def MyModule.do_something
OR
或者
def do_something
In what kind of cases would it be useful to have the function available to be mixed in, or to be used as a static method?
在什么样的情况下,可以将函数混入或用作静态方法是有用的?
采纳答案by Stefan Kanev
Think of Enumerable.
想想Enumerable。
This is the perfect example of when you need to include it in a module. If your class defines #each, you get a lot of goodness just by including a module (#map, #select, etc.). This is the only case when I use modules as mixins - when the module provides functionality in terms of a few methods, defined in the class you include the module it. I can argue that this should be the only case in general.
这是何时需要将其包含在模块中的完美示例。如果你的类定义#each,你只需通过包括模块(得到了很多善良的#map,#select等等)。这是我使用模块作为 mixins 的唯一情况 - 当模块根据一些方法提供功能时,在包含模块的类中定义。我可以争辩说,这应该是一般情况下的唯一情况。
As for defining "static" methods, a better approach would be:
至于定义“静态”方法,更好的方法是:
module MyModule
def self.do_something
end
end
You don't really need to call #module_function. I think it is just weird legacy stuff.
你真的不需要打电话#module_function。我认为这只是奇怪的遗留问题。
You can even do this:
你甚至可以这样做:
module MyModule
extend self
def do_something
end
end
...but it won't work well if you also want to include the module somewhere. I suggest avoiding it until you learn the subtleties of the Ruby metaprogramming.
...但如果您还想在某处包含该模块,它将无法正常工作。我建议在您了解 Ruby 元编程的精妙之处之前避免使用它。
Finally, if you just do:
最后,如果你只是这样做:
def do_something
end
...it will not end up as a global function, but as a private method on Object(there are no functions in Ruby, just methods). There are two downsides. First, you don't have namespacing - if you define another function with the same name, it's the one that gets evaluated later that you get. Second, if you have functionality implemented in terms of #method_missing, having a private method in Objectwill shadow it. And finally, monkey patching Objectis just evil business :)
...它最终不会成为一个全局函数,而是作为一个私有方法Object(在 Ruby 中没有函数,只有方法)。有两个缺点。首先,你没有命名空间——如果你定义了另一个同名的函数,它就是你得到的稍后被评估的函数。其次,如果您在 方面实现了功能,那么在 中#method_missing有一个私有方法Object会影响它。最后,猴子修补Object只是邪恶的事情:)
EDIT:
编辑:
module_functioncan be used in a way similar to private:
module_function可以以类似于以下方式使用private:
module Something
def foo
puts 'foo'
end
module_function
def bar
puts 'bar'
end
end
That way, you can call Something.bar, but not not Something.foo. If you define any other methods after this call to module_function, they would also be available without mixing in.
这样,您可以调用Something.bar,但不能调用Something.foo。如果您在此调用之后定义任何其他方法module_function,它们也将可用而无需混入。
I don't like it for two reasons, though. First, modules that are both mixed in and have "static" methods sound a bit dodgy. There might be valid cases, but it won't be that often. As I said, I prefer either to use a module as a namespace or mix it in, but not both.
不过,我不喜欢它有两个原因。首先,既混入又具有“静态”方法的模块听起来有点狡猾。可能有有效的案例,但不会那么频繁。正如我所说,我更喜欢将模块用作命名空间或将其混合使用,但不能两者兼而有之。
Second, in this example, barwould also be available to classes/modules that mix in Something. I'm not sure when this is desirable, since either the method uses selfand it has to be mixed in, or doesn't and then it does not need to be mixed in.
其次,在此示例中,bar也可用于混合Something. 我不确定这何时是可取的,因为该方法使用self并且必须混合,或者不使用然后不需要混合。
I think using module_functionwithout passing the name of the method is used quite more often than with. Same goes for privateand protected.
我认为 usingmodule_function而不传递方法的名称比 with 更频繁地使用。这同样适用于private和protected。
回答by J-_-L
It's a good way for a Ruby library to offer functionality that does not use (much) internal state. So if you (e.g.) want to offer a sinfunction and don't want to pollute the "global" (Object) namespace, you can define it as class method under a constant (Math).
这是 Ruby 库提供不使用(过多)内部状态的功能的好方法。因此,如果您(例如)想要提供一个sin函数并且不想污染“全局”( Object) 命名空间,您可以将其定义为常量 ( Math)下的类方法。
However, an app developer, who wants to write a mathematical application, might need sinevery two lines. If the method is also an instance method, she can just include the Math(or My::Awesome::Nested::Library) module and can now directly call sin(stdlib example).
但是,想要编写数学应用程序的应用程序开发人员可能需要sin每两行代码。如果该方法也是一个实例方法,她可以只包含Math(或My::Awesome::Nested::Library)模块,现在可以直接调用sin(stdlib 示例)。
It's really about making a library more comfortable for its users. They can choose themself, if they want the functionality of your library on the top level.
这实际上是为了让图书馆对其用户更舒适。如果他们想要顶级库的功能,他们可以自己选择。
By the way, you can achieve a similar functionality like module_functionby using: extend self(in the first line of the module). To my mind, it looks better and makes things a bit clearer to understand.
顺便说一句,您可以module_function使用以下方法实现类似的功能:(extend self在模块的第一行)。在我看来,它看起来更好,让事情更容易理解。
Update:More background info in this blog article.
更新:此博客文章中的更多背景信息。
回答by TalkativeTree
If you want to look at a working example, check out the chronic gem:
如果您想查看一个工作示例,请查看慢性宝石:
https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb
https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb
and Handlers is being included in the Parser class here:
和 Handlers 被包含在 Parser 类中:
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
He's using module_function to send the methods from Handlers to specific instances of Handler using that instance's invoke method.
他使用 module_function 将方法从 Handlers 发送到使用该实例的 invoke 方法的 Handler 的特定实例。

