我有以下内容:

class Test
    @@a = 10

    def show_a()
        puts "a: #{@@a}"
    end

    class << self
      @@b = '40'

      def show_b
        puts "b: #{@@b}"
    end
  end
end

为什么以下工作:

Test.instance_eval{show_b}
b: 40
=> nil

但是我无法访问 @@b 直接地?

Test.instance_eval{ @@b }
NameError: uninitialized class variable @@b in Object

同样,以下作品

t = Test.new
t.instance_eval{show_a}
a: 10
=> nil

但是以下失败

t.instance_eval{ @@a }
NameError: uninitialized class variable @@a in Object

我不明白为什么我无法直接从 instance_eval 块。

有帮助吗?

解决方案

在Rubykaigi派对上,我只是向Matz问了同样的问题。我半滴了,但他非常清醒,所以您可以将其作为确定的答案。

Anton是正确的 - 您无法通过instance_eval()访问类变量的原因是“只是因为”。甚至class_eval()也共享了相同的问题(MATZ本人对Class_eval()不确定,直到我告诉他我已经尝试过)。更具体地说:在范围方面,类变量比实例变量更像常数,因此切换自我(如instance_eval()和class_eval()do)在访问它们时不会有任何区别。

通常,避免完全避免班级变量可能是一个好主意。

其他提示

编辑: 下面的代码用1.8.7和1.9.1进行了测试...似乎以1.9.2:/的方式再次不同。

情况实际上并不是那么直接。行为有差异,具体取决于您使用的是1.8还是1.9以及是否正在使用 class_eval 或者 instance_eval.

下面的示例详细介绍了大多数情况下的行为。

我还将常数的行为包括在内,因为它们的行为与阶级变量相似,但并不完全相同。

类变量

class_eval 在红宝石1.8中:

class Hello
    @@foo = :foo
end

Hello.class_eval { @@foo } #=> uninitialized class variable

class_eval 在红宝石1.9中:

Hello.class_eval { @@foo } #=> :foo

所以类变量 使用时以1.9(但不在1.8中)抬头 class_eval

instance_eval 在红宝石1.8中 1.9

Hello.instance_eval { @@foo } #=> uninitialized class variable
Hello.new.instance_eval { @@foo } #=> uninitialized class variable

看起来类变量是 不是 在1.8中抬头 或者 1.9使用时 instance_eval

有趣的是 常数:

常数

class_eval 在红宝石1.8中

class Hello
    Foo = :foo
end

Hello.class_eval { Foo } #=> uninitialized constant

class_eval 在红宝石1.9中

Hello.class_eval { Foo } #=> :foo

因此,与班级变量一样,常数在1.9中被查找,但是 不是 在1.8中 class_eval

instance_eval 在红宝石1.8中

Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> uninitialized constant

instance_eval 在红宝石1.9中

Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> :foo

看来恒定查找并不类似于类变量查找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 ...

红宝石2.1

这是我发现访问类变量的最简洁和语义上最正确的方法:

class Hello
    @@foo = :foo_value
end

Hello.class_variable_get :@@foo  #=> :foo_value
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top