这是我的代码:
class Klass
["thing", nil].each do |i|
instance_variable_set("@#{i}reqs", {})
end
def initialize(var)
@reqs[var] = self
end
end
Klass.new("hello")
Run Code Online (Sandbox Code Playgroud)
这给了我错误:
in initialize': undefined method[] ='for nil:NilClass(NoMethodError)
我不应该得到这个错误,因为顶部的循环应该在它的第二次迭代中初始化@reqs.到底是怎么回事?
实例变量属于特定实例.这就是为什么它们被称为实例变量.
在第3行中,设置@reqs对象调用的实例变量Klass.在第6行中,您将访问名为@reqs该类实例的实例变量Klass.这是两个完全不同的,不同的对象,每个对象都有自己的一组实例变量.哎呀,这两个对象甚至都没有同一个类!(Klass班级是Class,而Klass.new班级是Klass.)
在第6行中,@reqs未初始化,未初始化的实例变量评估为nil.
有许多不同的方法可以解决这个问题,具体取决于你的具体情况和要求,最简单的方法是在initialize方法中初始化实例变量,毕竟,那就是那个方法:
class Klass
def initialize(var)
['thing', nil].each do |i|
instance_variable_set(:"@#{i}reqs", {})
end
@reqs[var] = self
end
end
Klass.new('hello')
Run Code Online (Sandbox Code Playgroud)
请记住,问题是实例变量在一个对象中初始化,在另一个对象中访问.此解决方案将初始化移动到正在执行读取的同一对象.
但是,双重也是可能的:将读数移动到初始化变量所在的位置:
class Klass
['thing', nil].each do |i|
instance_variable_set(:"@#{i}reqs", {})
end
def initialize(var)
self.class.instance_variable_get(:@reqs)[var] = self
end
end
Klass.new('hello')
Run Code Online (Sandbox Code Playgroud)
这有点难看,所以让我们添加一个attr_reader:
class Klass
['thing', nil].each do |i|
instance_variable_set(:"@#{i}reqs", {})
end
class << self; attr_reader :reqs end
def initialize(var)
self.class.reqs[var] = self
end
end
Klass.new('hello')
Run Code Online (Sandbox Code Playgroud)
显然,这两个做的事情非常不同.从你的问题中不清楚你真正想要的两个中的哪一个.
第三种可能是使用类变量:
class Klass
['thing', nil].each do |i|
class_variable_set(:"@@#{i}reqs", {})
end
def initialize(var)
@@reqs[var] = self
end
end
Klass.new('hello')
Run Code Online (Sandbox Code Playgroud)
请注意,这是另一回事.同样,无论你是否想要,你的问题都不清楚.