模块中的实例方法

fre*_*ght 20 ruby module instance

请考虑以下代码:

module ModName
  def aux
    puts 'aux'
  end
end
Run Code Online (Sandbox Code Playgroud)

如果我们替换moduleclass,我们可以做到以下几点:

ModName.new.aux
Run Code Online (Sandbox Code Playgroud)

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

Chu*_*uck 22

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

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

它们还充当命名空间的替代品,因为每个模块都定义了命名空间.但那有些不相干.(顺便说一句,类也有自己的命名空间,但是使它成为一个类意味着你将创建它的实例,因此它们在概念上是错误的.)

  • 一个真实世界的用例就是使用Sinatra的`helper`方法,该方法接受一个模块并将其混合到请求中.如果你的模块方法不依赖于状态(例如一个格式化传递给它的字符串的函数),那么它们也可以在外部称为"MyHelperModule.foo(bar)".使用`module_function`(根据下面的@JPabloFernández的答案)允许单个模块'instance'方法作为OP请求进行访问. (2认同)

pup*_*eno 20

你可以这样做:

module ModName
  def aux
    puts 'aux'
  end
  module_function :aux
end
Run Code Online (Sandbox Code Playgroud)

然后只需调用它:

ModName.aux
Run Code Online (Sandbox Code Playgroud)

  • 另外:如果你使用模块**作为命名空间,`extend self`是一个更清晰的选项,可以将每个方法定义为module_function. (4认同)
  • @yaauie 如果您没有将参数传递给`module_funciton`,那么它下面的任何函数都将成为模块函数。它的工作方式与“私有”相同。 (2认同)

Edv*_*rdM 15

你也可以说

module ModName
  extend self

  def aux
    puts 'aux'
  end
end
Run Code Online (Sandbox Code Playgroud)

然后你可以正常包含模块,也可以通过ModName调用方法.


Jör*_*tag 6

模块定义评估为"这是......",为什么?

在Ruby中,一切都是表达式,没有语句或声明.这意味着每次迭代都会计算出一个值.(但是,这并不一定意味着它计算为有用的值.例如,puts方法总是求值nil,就像def方法定义表达式一样(Rubinius除外,其中def表达式求值为CompiledMethod定义方法的对象) .)

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

在您的情况下,模块定义主体内的最后一个表达式是赋值.但是,作业?回归到底是什么?这不是一个声明吗?不,不是Ruby.一切都是表达式,赋值也不例外:赋值表达式求值为右侧评估的任何值.这里,赋值表达式的右侧是一个字符串文字,它的计算结果为字符串对象.

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

  • 自Joerg的答案以来,这个问题经过大量编辑,如果有人对他所谈论的内容感到有些困惑. (6认同)