消失的实例var

the*_*ter 0 ruby

这是我的代码:

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.到底是怎么回事?

Jör*_*tag 7

实例变量属于特定实例.这就是为什么它们被称为实例变量.

在第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)

请注意,这是另一回事.同样,无论你是否想要,你的问题都不清楚.