如何在模块中初始化ruby类变量

时间:2014-08-20 22:32:20

标签: ruby

假设我有这样的代码:

class TestClass
  module ClassMethods
    attr_accessor :number

    def initialize
      @number = 47
    end
  end

  include ClassMethods
  extend ClassMethods
end

TestClass.new.number会返回47,这是预期的,但TestClass.number会返回nil

如何为number类和TestClass个实例初始化TestClass变量? 到目前为止,我已经这样做了:

class TestClass
  module ClassMethods
    attr_accessor :number

    def initialize
      @number = 47
    end
  end

  include ClassMethods
  extend ClassMethods
  @number = 47
end

我不喜欢这种方法,因为number在两个地方初始化。

1 个答案:

答案 0 :(得分:1)

假设你有这个:

class TestClass
  module ClassMethods
    attr_accessor :number    
    def initialize
      @number = 47
    end
  end
  include ClassMethods
  extend  ClassMethods
end

让我们获取有关此课程的一些信息:

TestClass.instance_variables #=> []

毫不奇怪。

tc = TestClass.new      #=> #<TestClass:0x00000101098a10 @number=47>
p tc.instance_variables #=> [:@number]
tc.number               #=> 47
tc.number = 11

一切如预期。实例变量@numberinitialize创建,我们可以使用访问器检查和更改其值。

extend使TestClass#initialize成为了一个类方法,但尚未调用它。让我们调用它来初始化类实例变量@number

TestClass.initialize
  #=> NoMethodError: private method `initialize' called for TestClass:Class

啊,是的,initialize是私有方法。

TestClass.methods.include?(:initialize)         #=> false
TestClass.private_methods.include?(:initialize) #=> true

我们不能以通常的方式调用私有类方法。但是,send适用于私有方法和公共方法:

TestClass.send :initialize                      #=> 47
TestClass.instance_variables                    #=> [:@number]
TestClass.instance_variable_get(:@number)       #=> 47

所以现在已经创建了类实例变量,其设置等于47。它是否更改了实例变量@number的值?

tc.number                                       #=> 11

它没有改变。现在让我们更改类实例变量的值,然后查看实例变量的值是否受到影响:

TestClass.instance_variable_set(:@number, -5)   #=> -5
tc.number                                       #=> 11

如果您要为类实例变量@number添加访问器,请将此行添加到类或模块中:

Module.instance_eval("attr_accessor :number")

(有关解释,请参阅我的回答here。)

然后测试:

TestClass.number       #=> -5
TestClass.number = 107
TestClass.number       #=> 107