假设我有这样的代码:
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
在两个地方初始化。
答案 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
一切如预期。实例变量@number
由initialize
创建,我们可以使用访问器检查和更改其值。
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