23

考虑以下代码:

module ModName
  def aux
    puts 'aux'
  end
end

如果我们替换moduleclass,我们可以执行以下操作:

ModName.new.aux

但是,模块不能被实例化。有没有办法调用aux模块上的方法?

4

6 回答 6

23

想想是什么aux。什么对象会响应aux?这是一个实例方法,这意味着包含 ModName 的类的实例将响应它。ModName 模块本身不是此类的实例。如果您将 ModName 定义为一个类,这也将不起作用——您不能在没有实例的情况下调用实例方法。

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

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

于 2009-11-24T02:19:37.737 回答
22

你可以这样做:

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

然后就叫它:

ModName.aux
于 2009-12-25T19:42:51.620 回答
16

你也可以说

module ModName
  extend self

  def aux
    puts 'aux'
  end
end

然后就可以正常包含模块了,也可以通过 ModName 调用方法。

于 2011-05-10T15:05:16.160 回答
6

模块定义评估为“这是……”,为什么?

在 Ruby 中,一切都是表达式,没有语句或声明。这意味着一切都评估为一个值。(然而,这并不一定意味着它的计算结果是一个有用的值。例如,puts方法总是计算结果为nil,就像def方法定义表达式一样(在 Rubinius 中,def表达式计算结果为CompiledMethod正在定义的方法的对象) .)

那么,如果所有内容都计算为一个值,那么模块定义表达式的计算结果应该是什么?好吧,有几个候选者:它可以评估为nil,就像方法定义表达式一样。或者它可以评估模块对象本身,毕竟这我们定义的,对吧?但实际上,Matz 选择了第三个选项:模块(和类)定义表达式实际上评估为模块定义主体内的最后一个表达式评估为的任何值。(这允许您通过将nilorself作为最后一个表达式放入模块定义主体中来轻松模拟其他两种可能性。)

在您的情况下,模块定义主体内的最后一个表达式是一个赋值。但是,任务?这到底是什么回报?这不是声明吗?不,不是在 Ruby 中。一切都是一个表达式,赋值也不例外:赋值表达式求得右手边求得的值。在这里,赋值表达式的右侧是一个字符串文字,它的计算结果是一个字符串对象。

因此,整个模块定义表达式的计算结果为 string 'this is a const in module'

于 2009-11-24T02:36:58.467 回答
2

还有一点……

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"
于 2013-05-01T11:19:14.467 回答
0
class Foo
  include ModName
end
Foo.new.aux
# output: aux
于 2009-11-24T02:45:07.623 回答