ruby module_function vs包含模块

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而不传递方法的名称比使用更频繁.这同样适用于privateprotected.

  • 在最后一个带有`module_function`的例子中还有一个问题:无法从`bar`里面访问"private"函数`foo`,因为`foo`是一个实例方法(它没有`self`),并且只有在某个类中混合使用此模块时才能调用它.当它是一个仅用于命名空间的独立模块时不可能.那怎么样呢?如何将模块用于命名空间并隐藏一些来自外部世界的实现辅助函数,但允许它们通过其接口方法调用? (3认同)

J-_*_*_-L 15

这是Ruby库提供不使用(很多)内部状态的功能的好方法.因此,如果您(例如)想要提供sin函数并且不想污染"global"(Object)命名空间,则可以在constant(Math)下将其定义为类方法.

但是,想要编写数学应用程序的应用程序开发人员可能需要sin每两行.如果该方法也是一个实例方法,她可以只包含Math(或My::Awesome::Nested::Library)模块,现在可以直接调用sin(stdlib示例).

这真的是为了让图书馆的用户更舒适.如果他们希望您的图书馆的功能在顶层,他们可以选择自己.

顺便说一句,您可以实现类似的功能,例如module_function:使用:( extend self在模块的第一行).在我看来,它看起来更好,让事情更清楚一点.

更新:此博客文章中的更多背景信息.

  • [ruby styleguide](https://github.com/bbatsov/ruby-style-guide#classes--modules)喜欢``module_function``而不是``extend self`` (3认同)
  • 谢谢你的指针.不过,我不同意.`module_function`对初学者来说可能更友好,但是每个做严肃Ruby的人都应该能够阅读和理解`extend self`版本.`extend self`不那么抽象.它使用Ruby的基础工具集,而`module_function`可以从Ruby中删除,而不会丢失重要的功能. (3认同)