为什么我不能在ruby中调用类方法中的include?

时间:2011-09-03 21:11:45

标签: ruby

您可以调用include来将模块与ruby中的类混合,但必须在类定义的开头进行。为什么不能在类函数内完成?是否有替代语法?

EX:

module UsefulThings
  def a() puts "a" end
end

class IncludeTester
  include UsefulThings
    def initialize
  end
end

n = IncludeTester.new
n.a()

^^这样可行,但如果我将IncludeTester更改为以下内容,则会收到错误“undefined method`include'”

class IncludeTester
  def initialize
    include UsefulThings
  end
end

4 个答案:

答案 0 :(得分:6)

可以在类方法中完成。

这有效:

module UsefulThings
  def a
    puts "a" 
  end
end

class IncludeTester
  def self.mix_in_useful_things
    include UsefulThings
  end 
end

x = IncludeTester.new

IncludeTester.mix_in_useful_things

x.a # => a

但“initialize”不是类方法,而是实例方法。

“new”是一种类方法。您可以将new视为分配新对象,然后对其进行初始化,将初始化的参数传递给new。

你不能直接在initialize中调用include,因为include是Class的私有方法(继承自Module),而不是新创建的IncludeTester实例。

如果要将模块包含在实例方法的类中,则必须执行以下操作:

class IncludeTester
  def initialize
    self.class.send(:include, UsefulThings)
  end
end

这里有必要使用“send”,因为include是私有方法,这意味着它只能用隐式接收器(self)直接调用。

当你在类定义中正常调用initialize时,你实际上是用一个隐含的“self”接收器来调用它,指的是被定义的类。

这是执行此操作时实际发生的情况:

class IncludeTester
  include UsefulThings
end

答案 1 :(得分:4)

include是Module的一个方法,Module是Class的超类,因此include是Class上的一个方法,它使它成为IncludeTester中的一个类方法。当你这样做时:

class IncludeTester
  def initialize
    include UsefulThings
  end
end

你试图在实例方法中调用类方法而Ruby说

  

`initialize':未定义的方法`include'

因为没有名为include的实例方法。如果要在实例方法(例如initialize)中调用类方法,则执行以下操作:

def initialize
  self.class.include UsefulThings
end

但这不起作用,因为include是私有方法;你可以用class_eval解决这个问题:

def initialize
  self.class.class_eval {
    include UsefulThings
  }
end

每次实例化include UsefulThings时,您都会执行IncludeTester,除了没有多大意义之外,如果UsefulThingsincluded方法,则可能会导致问题。

答案 2 :(得分:2)

实际上完全可以从类方法中包含一个模块,如下所示:

module Stuff
  def say_hello
    puts "hello"
  end
end

class Foo
  def self.i_am_a_class_method
    include Stuff
  end

  def i_am_an_instance_method
  end
end

但是,您无法从实例方法执行此操作,因为include method仅可用作私有类方法,因此无法从Foo.new实例访问。

答案 3 :(得分:0)

您需要extend方法:

class IncludeTester
  def initialize
    extend UsefulThings
  end
end

这不需要在方法中完成:

IncludeTester.new.tap { |newTester| newTester.extend(UsefulThings) }