har*_*ell 22 ruby variables class instance-eval
我有以下内容:
class Test
@@a = 10
def show_a()
puts "a: #{@@a}"
end
class << self
@@b = '40'
def show_b
puts "b: #{@@b}"
end
end
end
Run Code Online (Sandbox Code Playgroud)
为什么以下工作:
Test.instance_eval{show_b}
b: 40
=> nil
Run Code Online (Sandbox Code Playgroud)
但我无法@@b直接访问?
Test.instance_eval{ @@b }
NameError: uninitialized class variable @@b in Object
Run Code Online (Sandbox Code Playgroud)
同样,以下工作
t = Test.new
t.instance_eval{show_a}
a: 10
=> nil
Run Code Online (Sandbox Code Playgroud)
但是以下失败了
t.instance_eval{ @@a }
NameError: uninitialized class variable @@a in Object
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我不能直接从instance_eval块访问类变量.
Pao*_*tta 17
我在RubyKaigi派对期间向Matz提出了同样的问题.我喝醉了一半,但他非常清醒,所以你可以把它作为明确的答案.
Anton是对的 - 你不能通过instance_eval()访问类变量的原因是"只是因为".即使class_eval()也有同样的问题(Matz本人对class_eval()并不完全确定,直到我告诉他我已经尝试过了).更具体地说:范围方面,类变量更像是常量而不是实例变量,因此切换self(如instance_eval()和class_eval()do)在访问它们时不会有任何区别.
通常,完全避免类变量可能是个好主意.
hor*_*guy 16
编辑:下面的代码用1.8.7和1.9.1测试......似乎情况与1.9.2再次不同:/
实际情况并非如此直截了当.行为上存在差异,具体取决于您使用的是1.8还是1.9以及是否正在使用class_eval或instance_eval.
以下示例详细说明了大多数情况下的行为.
我还包括了常量的行为,这是好的衡量标准,因为它们的行为类似于类变量,但不完全相同.
class_eval 在Ruby 1.8中:
class Hello
@@foo = :foo
end
Hello.class_eval { @@foo } #=> uninitialized class variable
Run Code Online (Sandbox Code Playgroud)
class_eval 在Ruby 1.9中:
Hello.class_eval { @@foo } #=> :foo
Run Code Online (Sandbox Code Playgroud)
所以当使用时,类变量在1.9 中查找(但不在1.8中)class_eval
instance_eval在Ruby 1.8 和 1.9中
Hello.instance_eval { @@foo } #=> uninitialized class variable
Hello.new.instance_eval { @@foo } #=> uninitialized class variable
Run Code Online (Sandbox Code Playgroud)
在使用时,似乎没有在1.8 或 1.9中查找类变量instance_eval
有趣的是常量的情况:
class_eval 在Ruby 1.8中
class Hello
Foo = :foo
end
Hello.class_eval { Foo } #=> uninitialized constant
Run Code Online (Sandbox Code Playgroud)
class_eval 在Ruby 1.9中
Hello.class_eval { Foo } #=> :foo
Run Code Online (Sandbox Code Playgroud)
因此,与类变量一样,常量在1.9中查找,但不在 1.8中查找class_eval
instance_eval 在Ruby 1.8中
Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> uninitialized constant
Run Code Online (Sandbox Code Playgroud)
instance_eval 在Ruby 1.9中
Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> :foo
Run Code Online (Sandbox Code Playgroud)
似乎常量查找与Ruby 1.9的类变量查找不太相似.一个Hello实例确实获得访问不变,而Hello类没有.
好吧,可能最好的答案是"只是因为":简而言之,instance_eval创建了一种使用给定对象绑定调用的单例proc.我同意这听起来有点奇怪,但事实就是如此.
如果使用字符串执行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 ...
Run Code Online (Sandbox Code Playgroud)