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