如何定义模块Math中的模块方法?

时间:2013-08-02 03:01:58

标签: ruby

Math中的方法可以像类方法一样调用:

Math.cos(0)

但也可以是include - d像实例方法:

include Math
cos(0)

相反,以下模块可以用一种方式调用,但不能用另一种方式调用:

module Foo
  def bar
  end
end

Foo.bar() # NoMethodError for this call
include Foo
bar()     # but this call is fine

单身方法:

module Foo
  def self.bar
  end
end

Foo.bar() # this call is fine
include Foo
bar()     # but not this one

知道如何编写像Math这样的模块吗?

2 个答案:

答案 0 :(得分:12)

有几种方法可以获得单身方法,所以我将首先考虑这些方法。我们将在一分钟内找到让include Math工作的部分。所以,首先,如果您在模块或类体中,可以将单例方法定义为self的方法,如下所示:

module Foo
  # Define bar as a method on self (the Foo module), thereby making
  # it a singleton method.
  def self.bar
    "baz"
  end
end

或者,您可以将它们定义为模块或类的单例类上的方法:

module Foo
  # Opens the singleton class of self (the Foo module). This makes
  # bar a singleton method (see Module#define_singleton_method for
  # some more on that).
  class <<self
    def bar
      "baz"
    end
  end
end

include Math,拥有你的方法,并且吃它们

第三,如果您希望方法同时作为实例和单例方法,则可以使用extend。这允许您将模块包含在某处并且无需限定地调用其方法,或者至少具有不同的限定条件,具体取决于您包含模块的位置(但是,这类型超出了此范围)。您还可以extend self或使用其他模块(包含实例方法)进行扩展,以便在模块或类体中将它们添加为单例方法。这可能听起来比看起来更复杂:

module Foo
  def bar
    "baz"
  end

  # Extending self will add the instance methods of self as
  # methods on the object self -- which happens to be a module,
  # so you basically get class methods from the instance methods.
  extend self
end

最后一种情况允许您同时include另一个模块或类中的模块并获得bar作为实例方法,所以你做什么取决于什么你需要。一般来说,如果我只是定义一个单身方法而且我只需要它,我更喜欢第一条路线。第二个选项或多或少相同,但也允许您使用alias_method等。就我而言,合格的访问与敬虔相邻。

然而,第三个选项 - 使用extend self - 有助于您使用include Math执行您要求的内容,您希望能够将函数调用为单例方法(Math.cos(0))并包含访问和调用方法的模块,而不用模块名称(cos(0))对它们进行限定。如果您需要,可以执行以下操作之一:

  1. 将方法定义两次,既可以是单例方法,也可以是实例方法。这不是首选。
  2. 在另一个模块中定义它们,并使用该模块包含和扩展。如果您想在多个地方使用该模块,这很方便。
  3. extend self。使用self进行扩展可能是最佳选择,因为它很简单,减少了重复代码,并且足以满足问题的目的。
  4. 所以你去,实例方法和单身方法和谐地生活在一起,就像Holan和Hamlet一样。

答案 1 :(得分:3)

这就是Module#module_function的用途。