Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 消失实例变量_Ruby - Fatal编程技术网

Ruby 消失实例变量

Ruby 消失实例变量,ruby,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") 这给了我一个错误: 在initialize]中:对于nil:NilClass(NoMethodError),未定义方法 我不应该得到这个错误,因为顶部的

这是我的密码:

class Klass
  ["thing", nil].each do |i|
    instance_variable_set("@#{i}reqs", {})
  end

  def initialize(var)
    @reqs[var] = self
  end
end

Klass.new("hello")
这给了我一个错误:

initialize]中:对于nil:NilClass(NoMethodError),未定义方法


我不应该得到这个错误,因为顶部的循环应该在第二次迭代中初始化@reqs。发生了什么?

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

在第3行中,设置对象
Klass
的名为
@reqs
的实例变量。在第6行中,访问类
Klass
实例的名为
@reqs
的实例变量。这是两个完全不同的对象,每个对象都有自己的实例变量集。见鬼,这两个对象甚至没有相同的类!(
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')
记住,问题是实例变量在一个对象中初始化,在另一个对象中访问。此解决方案将初始化移动到执行读取的同一对象

但是,也可以使用双精度:将读数移动到初始化变量的位置:

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')
这有点难看,所以让我们添加一个
attr\u阅读器

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')

请注意,这还做了另一件不同的事情。同样,您的问题并不清楚您是否想要这样做。

顶部的循环是为类定义实例变量,而不是为类的任何对象定义实例变量

因此,对于对象,它不存在

从外观上看,您需要一个对整个类通用的哈希,在该类中,您将在哈希中存储每个创建的对象。假设类继承没有问题,最好使用类变量

所以


如果您这样定义类:

class Klass
  instance_variable_set(:@name, 'dog')

  def self.name
    @name
  end

  def name
    @name
  end
end
然后


现在你可以看到区别了。您的变量是在类级别上定义的,而不是在实例级别上定义的。

这里没有理由使用类变量。如果他想要一个散列,其中一个键
名称
存储对象本身,那听起来像是他想要以不同的名称存储所有对象。。。很容易推断出他想要一个类变量(或类级别的实例变量),就丑陋而言,不是
['thing',nil];结束
qualify?@CarySwoveland:就我个人而言,我看不出仅仅是
@@thingreqs,@@reqs={},{}
有什么不对,但我想保持原始代码的感觉。情人眼里出西施,但我发现
类变量集(:@@thingreqs,{});class_variable_set(:@@reqs,{})
越来越清晰。@CarySwoveland:在这种情况下,由于名称是静态已知的,并且只有两个,老实说,我看不出有任何理由使用元编程(即
class_variable_set
)。只是
@@thingreqs、@@reqs={}、{}
@@thingreqs={}@@reqs={}
或类似的东西,但正如我所说的,我希望保留原始代码的感觉。这也很明显,问题不在于元编程或
每个
块的闭包属性,而在于动态实例范围的闭包属性。
class Klass
    ["thing",nil].each do |i|
        class_variable_set("@@#{i}reqs", {})
    end
    def initialize(var)
        @@reqs[var] = self
    end
end
Klass.new("hello")
class Klass
  instance_variable_set(:@name, 'dog')

  def self.name
    @name
  end

  def name
    @name
  end
end
Klass.name # => 'dog'

instance = Klass.new
instance.name # => nil