Ruby module_function 与包含模块

问题描述 投票:0回答:3

在 Ruby 中,我知道可以通过使用

module_function
来使用模块功能,而无需在模块中混合,如此处所示。我可以看到这是多么有用,因此您可以使用该功能而无需在模块中混合。

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

我的问题是为什么你可能希望以这两种方式定义函数。

为什么不直接拥有

def MyModule.do_something

def do_something

在什么情况下,可以混合使用该函数或将其用作静态方法?

ruby module mixins
3个回答
50
投票

想想可枚举

这是您需要将其包含在模块中的完美示例。如果您的类定义了

#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
也是如此。


16
投票

对于 Ruby 库来说,这是提供不使用(太多)内部状态的功能的好方法。因此,如果您(例如)想要提供

sin
函数并且不想污染“全局”(
Object
) 命名空间,则可以将其定义为常量 (
Math
) 下的类方法。

但是,想要编写数学应用程序的应用程序开发人员可能需要每两行

sin
。如果该方法也是实例方法,她可以只包含
Math
(或
My::Awesome::Nested::Library
)模块,现在可以直接调用
sin
(stdlib 示例)。

这实际上是为了让图书馆对用户来说更加舒适。如果他们想要您的库的功能处于顶层,他们可以自己选择。

顺便说一句,您可以通过使用:

module_function
(在模块的第一行)来实现类似
extend self
的功能。在我看来,它看起来更好,并且让事情更容易理解。

更新:更多背景信息请参见这篇博客文章


2
投票

如果你想看一个工作示例,请查看慢性宝石:

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 将方法从处理程序发送到处理程序的特定实例(使用该实例的调用方法)。

© www.soinside.com 2019 - 2024. All rights reserved.