是否可以从也在该模块中的类内部调用Module函数

时间:2010-07-01 16:37:39

标签: ruby

在这个Ruby代码中:

Module M
  Class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  def helper(param)
    puts "hello #{param}"
  end
end

当我尝试运行

时,我收到“未定义方法'助手',因为'M:模块'”错误
c = M::C.new("world")
c.work

但直接从另一个类调用M::helper("world")可以正常工作。类可以不调用在它们定义的同一模块中定义的模块函数吗?有没有办法解决这个问题,除了将课程移到模块之外?

4 个答案:

答案 0 :(得分:4)

你应该在self之前添加模块方法:

module M
  class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  def self.helper(param)
    puts "hello #{param}"
  end
end

答案 1 :(得分:4)

要调用M::helper,您需要将其定义为def self.helper; end 为了便于比较,请查看以下修改后的代码段

中的helper和helper2
module M
  class C < Struct.new(:param)
    include M     # include module to get helper2 mixed in
    def work
      M::helper(param)
      helper2(param)
    end
  end

  def self.helper(param)
    puts "hello #{param}"
  end

  def helper2(param)
    puts "Mixed in hello #{param}"
  end
end

c = M::C.new("world")
c.work

答案 2 :(得分:2)

C不在helper的单件类时,

M正试图在helper上致电M。另外,当它只是一种方法时,你会一直说helper是一个模块函数。使helper模块函数可以使代码工作:

module M
  class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  module_function

  def helper(param)
    puts "hello #{param}"
  end
end

在课程中包含该模块也可以:

module M
  class C < Struct.new(:param)
    include M

    def work
      helper(param)
    end
  end

  def helper(param)
    puts "hello #{param}"
  end
end

在第一个示例中,helper被放入M的单身类module_function。第二个示例将M的方法导入C,以便C可以使用它们。另一个区别是,在第一个中,您可以从代码中的任何位置调用M.helper。在第二个中,您可以在代码中的helper的任何实例中调用C。要解决此问题,请将helper设为私有:

module M
  class C < Struct.new(:param)
    include M

    def work
      helper(param)
    end
  end

  private
  def helper(param)
    puts "hello #{param}"
  end
end

答案 3 :(得分:1)

以下是一些解释:

来自ruby docs

  

模块是方法和常量的集合。模块中的方法可以是实例方法或模块方法。当包含模块时,实例方法在类中显示为方法,而模块方法则不包括。 相反,可以在不创建封装对象的情况下调用模块方法,而实例方法则可以不调用。 (参见模块#module_function。)

模块内的

self.methodname创建模块方法。

在这种情况下,当你从C ++开发人员的角度来看它时,你调用M::helper实际上是M.helper。在这种情况下,接收器是Module对象(ruby builtin type Module的一个实例)。

查看这个的其他方法是理解接收器概念,每个方法调用都包含一个接收器和方法名称(+可选的params和代码块)。 Receiver可以是Module objectClass object或用户定义类的实例。

您只能在Module(或Class)对象上调用Module(或Class)方法。您可以在实例上调用任何方法(模块/类/实例)。

如果要调用模块中定义的实例方法,则必须通过including在某个类中为该模块提供接收器并创建其实例。

因此,在这种情况下,另一种解决方案可以是:

module MM
  def helper(param)
    puts "hello #{param}"
  end

  class ReceiverClass
    include MM           # add helper() to ReceiverClass
  end

  class C < Struct.new(:param)
    def work
      ReceiverClass.new.helper(param)
    end
  end
end

c = MM::C.new("world")
c.work