Ruby 'module_function'与包括模块

mfpqipee  于 2023-10-18  发布在  Ruby
关注(0)|答案(3)|浏览(150)

在Ruby中,我理解模块函数可以通过使用module_function而不用在模块中混合使用,如这里所示。我可以看到这是如何有用的,所以你可以使用函数,而不会在模块中混合。

module MyModule
  def do_something
    puts "Hello, World!"
  end
  module_function :do_something
end

为什么要用这两种方式定义函数?
为什么不干脆

def MyModule.do_something

def do_something

在什么样的情况下,将函数混合在其中或用作静态方法是有用的?

e5nqia27

e5nqia271#

想想Enumerable
这是一个完美的例子,当你需要将它包含在一个模块中。如果你的类定义了#each,那么仅仅通过包含一个模块(#map#select等)就可以得到很多好处。这是我使用模块作为mixin的唯一情况-当模块提供一些方法的功能时,在类中定义,您包括模块。我可以说,这应该是唯一的情况一般。
至于定义“静态”方法,更好的方法是:

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而不传递方法名称比使用。privateprotected也是如此。

csbfibhn

csbfibhn2#

这是Ruby库提供不使用(太多)内部状态的功能的好方法。因此,如果你(例如)想要提供一个sin函数,并且不想污染“全局”(Object)命名空间,你可以将其定义为常量(Math)下的类方法。
然而,想要编写数学应用程序的应用程序开发人员可能需要每两行sin。如果该方法也是一个示例方法,她可以只包含Math(或My::Awesome::Nested::Library)模块,现在可以直接调用sin(stdlib示例)。
这实际上是为了让图书馆对用户更舒适。如果他们希望你的库的功能在顶层,他们可以自己选择。
顺便说一下,你可以通过使用以下命令实现类似于module_function的功能:extend self(在模块的第一行)。在我看来,它看起来更好,让事情更容易理解。

**更新:**更多背景信息在this blog article中。

2izufjch

2izufjch3#

如果你想看一个工作示例,请查看Chronic gem中的handlers.rb
处理程序被包含在parser.rb的Parser类中。
它使用 module_function 将方法从Handlers发送到特定的示例,并使用该示例的invoke方法。

相关问题