请考虑以下代码:
module ModName
def aux
puts 'aux'
end
end
如果我们将module
替换为class
,我们可以执行以下操作:
ModName.new.aux
但是,模块无法实例化。有没有办法在模块上调用aux
方法?
答案 0 :(得分:22)
想想aux
是什么。哪个对象会响应aux
?它是一个实例方法,这意味着包含ModName的类的实例将响应它。 ModName模块本身不是此类的实例。如果您已将ModName定义为类,则此操作也无效 - 您无法在没有实例的情况下调用实例方法。
模块非常类似于可以混合到其他类中以添加行为的类。当一个类混合在一个模块中时,所有模块的实例方法都成为该类的实例方法。这是实现多重继承的一种方式。
它们还充当命名空间的替代品,因为每个模块都定义了命名空间。但那有些不相干。 (顺便说一句,类也有自己的命名空间,但是使它成为一个类意味着你将创建它的实例,因此它们在概念上是错误的。)
答案 1 :(得分:20)
你可以这样做:
module ModName
def aux
puts 'aux'
end
module_function :aux
end
然后只需称呼它:
ModName.aux
答案 2 :(得分:15)
你也可以说
module ModName
extend self
def aux
puts 'aux'
end
end
然后你可以正常包含模块,也可以通过ModName调用方法。
答案 3 :(得分:6)
模块定义评估为“这是......”,为什么?
在Ruby中,一切都是表达式,没有语句或声明。这意味着每次迭代都会计算出一个值。 (但是,这并不一定意味着它会计算为有用的值。例如,puts
方法始终计算为nil
,就像def
一样方法定义表达式(Rubinius除外,其中def
表达式求值为所定义方法的CompiledMethod
对象。)
因此,如果所有内容都计算为值,那么模块定义表达式应该评估什么?好吧,有几个候选者:它可以评估为nil
,就像方法定义表达式一样。或者它可以评估模块对象本身,毕竟,这个是我们正在定义的,对吧?但实际上,Matz选择了第三种选择:模块(和类)定义表达式实际上评估模块定义体内的最后一个表达式求值。 (这使您可以通过将nil
或self
作为模块定义主体中的最后一个表达式来轻松模拟其他两种可能性。)
在您的情况下,模块定义主体内的最后一个表达式是赋值。但是,作业? 返回的是什么?这不是一个声明吗?不,不是Ruby。 Everything 是一个表达式,并且赋值也不例外:赋值表达式求值为右侧评估的任何值。这里,赋值表达式的右侧是一个字符串文字,它的计算结果为字符串对象。
因此,整个模块定义表达式的计算结果为字符串'this is a const in module'
。
答案 4 :(得分: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"
答案 5 :(得分:0)
class Foo
include ModName
end
Foo.new.aux
# output: aux