模块中的实例方法

24

考虑以下代码:

module ModName
  def aux
    puts 'aux'
  end
end
如果我们将module替换为class,就可以做到以下操作:
ModName.new.aux

模块无法实例化,但是有没有一种方法可以在模块上调用aux方法呢?


5
只需使用一次的话,您可以执行 Object.new.extend(ModeName).aux。该语句不需要解释其含义,我的任务是将其翻译为通俗易懂的中文并保持原意。 - AJcodez
6个回答

23

你可以这样做:

module ModName
  def aux
    puts 'aux'
  end
  module_function :aux
end

然后只需调用它:

ModName.aux

4
如果您将模块仅用作名称空间,那么使用"extend self"是定义每个方法为module_function的更清晰的选择。 - Ry Biesemeyer
3
如果您没有向 module_function 传递参数,则下面的任何函数都将成为模块函数。它的工作方式与 private 相同。 - LandonSchropp

23

考虑一下 aux 是什么。哪个对象会响应 aux?这是一个实例方法,这意味着包括 ModName 的类的实例将对其进行响应。ModName 模块本身不是这样一个类的实例。如果你将 ModName 定义为一个类,那么这也不会起作用 - 你不能在没有实例的情况下调用实例方法。

模块非常像可以混入到其他类中以添加行为的类。当一个类混入一个模块时,所有模块的实例方法都成为该类的实例方法。这是实现多重继承的一种方式。

它们还可以作为命名空间的替代品,因为每个模块定义了一个命名空间。但这与此无关。(顺便说一句,类也有它们自己的命名空间,但将其制作为类意味着您将创建它的实例,所以从概念上讲就是错误的。)


2
一个真实世界的应用是在Sinatra的helper方法中,它接受一个模块并将其混合到请求中。如果您的模块方法不依赖于状态(例如格式化传递给它的字符串的函数),它们也可以被作为MyHelperModule.foo(bar)外部调用。使用 module_function(根据@JPabloFernández下面的答案)允许单个模块'实例'方法被访问到OP所请求的方式。 - Phrogz

17
你也可以这么说。
module ModName
  extend self

  def aux
    puts 'aux'
  end
end

然后你可以正常地导入模块,但也可以通过 ModName 调用方法。


6
在Ruby中,一切都是表达式,没有语句或声明。这意味着每个表达式都会求值为一个值。(但这并不一定意味着它会求值为一个有用的值。例如,puts方法始终会求值为nil,就像def方法定义表达式一样(除了在Rubinius中,def表达式会求值为正在定义的方法的CompiledMethod对象)。)
那么,如果每个东西都会求值为一个值,模块定义表达式应该求值为什么呢?嗯,有几个可能性:它可以和方法定义表达式一样求值为nil。或者它可以在定义的模块对象本身上求值,毕竟这就是我们要定义的东西,对吧?但实际上,Matz选择了第三个选项:模块(和类)定义表达式实际上会求值为模块定义体内最后一个表达式所求得的值。(这使您可以轻松地通过将nil或self作为模块定义体内的最后一个表达式来模拟其他两种可能性。)
在您的情况下,模块定义体内最后一个表达式是一个赋值语句。但是,赋值语句?那返回什么呢?这不是一个语句吗?不,在Ruby中,所有东西都是表达式,赋值也不例外:赋值表达式会求值为其右侧所求得的值。在这里,赋值表达式的右侧是一个字符串字面量,它会求值为一个字符串对象。
因此,整个模块定义表达式会求值为字符串'this is a const in module'。

6
自从Joerg回答以来,这个问题已经被大量编辑过了,如果有人对他所说的内容感到有点困惑,请注意。 - Andrew Grimm

2

And a little more...

module Y
  def Y.a
    puts "a"
  end

  def Y.b
    c
  end

  def self.c
    puts "b -- c"
  end
end

调用(不带'.new'):

Y.a #=> "a"
Y.b #=> "b -- c"
Y.c #=> "b -- c"

1
Y.c 也可以。你还可以使用 module Y; class << self; def c; puts "b -- c"; end; end; 并在其特殊类上定义 ::c - Michael De Silva

0
class Foo
  include ModName
end
Foo.new.aux
# output: aux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接