在 Ruby 中,我知道可以通过使用
module_function
来使用模块功能,而无需在模块中混合,如此处所示。我可以看到这是多么有用,因此您可以使用该功能而无需在模块中混合。
module MyModule
def do_something
puts "hello world"
end
module_function :do_something
end
我的问题是为什么你可能希望以这两种方式定义函数。
为什么不直接拥有
def MyModule.do_something
或
def do_something
在什么情况下,可以混合使用该函数或将其用作静态方法?
想想可枚举。
这是您需要将其包含在模块中的完美示例。如果您的类定义了
#each
,那么只需包含一个模块(#map
、#select
等)即可获得很多好处。这是我使用模块作为 mixins 的唯一情况 - 当模块提供一些方法的功能时,在包含该模块的类中定义。我可以说这应该是唯一的情况。
对于定义“静态”方法,更好的方法是:
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
而不传递方法名称比 with 更常用。 private
和 protected
也是如此。
对于 Ruby 库来说,这是提供不使用(太多)内部状态的功能的好方法。因此,如果您(例如)想要提供
sin
函数并且不想污染“全局”(Object
) 命名空间,则可以将其定义为常量 (Math
) 下的类方法。
但是,想要编写数学应用程序的应用程序开发人员可能需要每两行
sin
。如果该方法也是实例方法,她可以只包含 Math
(或 My::Awesome::Nested::Library
)模块,现在可以直接调用 sin
(stdlib 示例)。
这实际上是为了让图书馆对用户来说更加舒适。如果他们想要您的库的功能处于顶层,他们可以自己选择。
顺便说一句,您可以通过使用:
module_function
(在模块的第一行)来实现类似extend self
的功能。在我看来,它看起来更好,并且让事情更容易理解。
更新:更多背景信息请参见这篇博客文章。
如果你想看一个工作示例,请查看慢性宝石:
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 将方法从处理程序发送到处理程序的特定实例(使用该实例的调用方法)。