[英]Accessing Ruby Class Variables with class_eval and instance_eval
I have the following: 我有以下内容:
class Test
@@a = 10
def show_a()
puts "a: #{@@a}"
end
class << self
@@b = '40'
def show_b
puts "b: #{@@b}"
end
end
end
Why does following work: 为什么以下工作:
Test.instance_eval{show_b}
b: 40
=> nil
But I can't access @@b
directly? 但我不能直接访问
@@b
?
Test.instance_eval{ @@b }
NameError: uninitialized class variable @@b in Object
Likewise, the following works 同样,以下工作
t = Test.new
t.instance_eval{show_a}
a: 10
=> nil
but the following fails 但是以下失败了
t.instance_eval{ @@a }
NameError: uninitialized class variable @@a in Object
I don't understand why I can't access the Class Variables directly from the instance_eval
blocks. 我不明白为什么我不能直接从
instance_eval
块访问类变量。
I just asked the same question to Matz during the RubyKaigi party. 我在RubyKaigi派对期间向Matz提出了同样的问题。 I was half-drunk, but he was perfectly sober, so you can take this as the definitive answer.
我喝醉了一半,但他非常清醒,所以你可以把它作为明确的答案。
Anton is right - the reason why you cannot access class variables through instance_eval() is "just because". Anton是对的 - 你不能通过instance_eval()访问类变量的原因是“只是因为”。 Even class_eval() shares the same issue (Matz himself wasn't totally sure about class_eval() until I told him I'd already tried it).
即使class_eval()也有同样的问题(Matz本人对class_eval()并不完全确定,直到我告诉他我已经尝试过了)。 More specifically: scope-wise, class variables are more like constants than instance variables, so switching self (as instance_eval() and class_eval() do) is not going to make any difference when it comes to accessing them.
更具体地说:范围方面,类变量更像是常量而不是实例变量,因此切换self(如instance_eval()和class_eval()do)在访问它们时不会有任何区别。
In general, it might be a good idea to avoid class variables altogether. 通常,完全避免类变量可能是个好主意。
EDIT: below code was tested with 1.8.7 and 1.9.1...it seems the situation is different again with 1.9.2 :/ 编辑:下面的代码用1.8.7和1.9.1测试......似乎情况与1.9.2再次不同:/
The situation actually isn't that straight forward. 实际情况并非如此直截了当。 There are differences in behaviour depending on whether you're using 1.8 or 1.9 and whether you're using
class_eval
or instance_eval
. 根据您使用的是1.8还是1.9以及是否使用
class_eval
或instance_eval
,行为存在差异。
The examples below detail the behaviour in most situations. 以下示例详细说明了大多数情况下的行为。
I also included the behaviour of constants, for good measure, as their behaviour is similar to, but not exactly the same as, class variables. 我还包括了常量的行为,这是好的衡量标准,因为它们的行为类似于类变量,但不完全相同。
class_eval
in Ruby 1.8: Ruby 1.8中的
class_eval
:
class Hello
@@foo = :foo
end
Hello.class_eval { @@foo } #=> uninitialized class variable
class_eval
in Ruby 1.9: Ruby 1.9中的
class_eval
:
Hello.class_eval { @@foo } #=> :foo
So class variables are looked up in 1.9 (but not in 1.8) when using class_eval
因此,当使用
class_eval
时,在1.9(但不是1.8) 中查找类变量
instance_eval
in Ruby 1.8 and 1.9 Ruby 1.8 和 1.9中的
instance_eval
Hello.instance_eval { @@foo } #=> uninitialized class variable
Hello.new.instance_eval { @@foo } #=> uninitialized class variable
It appears class variables are not looked up in 1.8 or 1.9 when using instance_eval
当使用
instance_eval
时,似乎没有在1.8 或 1.9中查找类变量
What is also interesting is the case for constants : 有趣的是常量的情况:
class_eval
in Ruby 1.8 Ruby 1.8中的
class_eval
class Hello
Foo = :foo
end
Hello.class_eval { Foo } #=> uninitialized constant
class_eval
in Ruby 1.9 Ruby 1.9中的
class_eval
Hello.class_eval { Foo } #=> :foo
So, as with class variables, constants are looked up in 1.9 but not in 1.8 for class_eval
因此,与类变量一样,常量在1.9中查找,但在
class_eval
不在 1.8中class_eval
instance_eval
in Ruby 1.8 Ruby 1.8中的
instance_eval
Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> uninitialized constant
instance_eval
in Ruby 1.9 Ruby 1.9中的
instance_eval
Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> :foo
It appears that constant lookup is not quite analogous to class variable look up for Ruby 1.9. 似乎常量查找与Ruby 1.9的类变量查找不太相似。 A
Hello
instance does get access to the constant while the Hello
class does not. Hello
实例确实可以访问常量,而Hello
类则不能。
Well, probably the best answer is "just because": the instance_eval in a nutshell creates some kind of singleton proc that is invoked with the binding of a given object. 好吧,可能最好的答案是“只是因为”:简而言之,instance_eval创建了一种使用给定对象绑定调用的单例proc。 I agree that is sounds a bit strange, but it is what it is.
我同意这听起来有点奇怪,但事实就是如此。
If you execute instance_eval with a string, you will even get a warning that your method tries to access class variable: 如果使用字符串执行instance_eval,您甚至会收到警告,告知您的方法尝试访问类变量:
irb(main):038:0> Test.new.instance_eval "@@a"
(eval):1: warning: class variable access from toplevel singleton method
NameError: (eval):1:in `irb_binding': uninitialized class variable ...
Ruby 2.1 Ruby 2.1
This is the most concise and semantically correct way I've found to access a class variable: 这是我发现访问类变量时最简洁和语义正确的方法:
class Hello
@@foo = :foo_value
end
Hello.class_variable_get :@@foo #=> :foo_value
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.