使用 class_eval 和 instance_eval 访问 Ruby 类变量

发布于 2024-09-13 12:51:52 字数 722 浏览 3 评论 0原文

我有以下内容:

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 块访问类变量。

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?

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

瀞厅☆埖开 2024-09-20 12:51:52

我刚刚在 RubyKaigi 聚会上向 Matz 提出了同样的问题。我已经喝得半醉了,但他却完全清醒,所以你可以将此作为确定的答案。

Anton 是对的 - 无法通过 instance_eval() 访问类变量的原因是“只是因为”。甚至 class_eval() 也有同样的问题(Matz 本人并不完全确定 class_eval() ,直到我告诉他我已经尝试过了)。更具体地说:就作用域而言,类变量更像常量而不是实例变量,因此在访问它们时切换 self(如 instance_eval() 和 class_eval() 所做的那样)不会产生任何差异。

一般来说,完全避免类变量可能是个好主意。

I just asked the same question to Matz during the RubyKaigi party. 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". 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). 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.

In general, it might be a good idea to avoid class variables altogether.

自找没趣 2024-09-20 12:51:52

编辑:下面的代码在 1.8.7 和 1.9.1 上进行了测试...似乎 1.9.2 的情况又有所不同:/

情况实际上并不是那么简单。根据您使用的是 1.8 还是 1.9 以及您使用的是 class_eval 还是 instance_eval,行为会有所不同。

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

为了更好的衡量,我还包括了常量的行为,因为它们的行为类似于类变量,但不完全相同。

Ruby 1.8 中的类变量

class_eval

class Hello
    @@foo = :foo
end

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

Ruby 1.9 中的 class_eval

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

所以类变量 使用 class_eval instance_eval 时在 1.9 中查找(但不在 1.8 中)

>在 Ruby 1.8 1.9 中

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

出现使用 instance_eval 时,类变量在 1.8 或 1.9 中查找。

常量的情况也很有趣。 :

常量

class_eval in Ruby 1.8

class Hello
    Foo = :foo
end

Hello.class_eval { Foo } #=> uninitialized constant

class_eval in Ruby 1.9

Hello.class_eval { Foo } #=> :foo

因此,与类变量一样,常量在以下位置查找1.9,但在 1.8 中,对于

Ruby 1.8 中的 class_eval instance_eval

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

instance_eval在 Ruby 1.9 中

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

看来常量查找与 Ruby 1.9 中的类变量查找不太相似。 Hello 实例确实可以访问常量,而 Hello 类则不能。

EDIT: below code was tested with 1.8.7 and 1.9.1...it seems the situation is different again with 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.

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 variables

class_eval in Ruby 1.8:

class Hello
    @@foo = :foo
end

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

class_eval in Ruby 1.9:

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

So class variables are looked up in 1.9 (but not in 1.8) when using class_eval

instance_eval in Ruby 1.8 and 1.9

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

What is also interesting is the case for constants:

Constants

class_eval in Ruby 1.8

class Hello
    Foo = :foo
end

Hello.class_eval { Foo } #=> uninitialized constant

class_eval in Ruby 1.9

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

instance_eval in Ruby 1.8

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

instance_eval in Ruby 1.9

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. A Hello instance does get access to the constant while the Hello class does not.

旧情别恋 2024-09-20 12:51:52

好吧,可能最好的答案是“只是因为”:简而言之,instance_eval 创建了某种通过给定对象的绑定来调用的单例过程。我同意这听起来有点奇怪,但事实就是如此。

如果您使用字符串执行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 ...

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. 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:

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 ...
风苍溪 2024-09-20 12:51:52

Ruby 2.1

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

class Hello
    @@foo = :foo_value
end

Hello.class_variable_get :@@foo  #=> :foo_value

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文