Ruby 关于元编程问题

cy1806152142 · 2017年02月25日 · 最后由 cy1806152142 回复于 2017年02月26日 · 1731 次阅读

Help!!!

最近在看 ruby 元编程 遇到如下问题 求大神赐教

代码如下
class AnotherClass
  @@v = 3       #类变量
  @v = 4          #类实例变量
end

class OneClass
  def add_method_to aClass
    aClass.class_eval do
      def self.new_method  #定义AnotherClass类的一个类方法
        p @v
        p @@v
      end
    end
  end 
end

obj = OneClass.new
obj.add_method_to(AnotherClass)
AnotherClass.new_method

问题概述

元编程中关于class_eval函数的描述: class_eval() 方法会同时修改 self 和当前类,通过修改当前类,class_eval() 实际上 是重新打开了该类,就像 class 关键字所做的一样。 如上所述,class_eval 打开了类,那么自然可以访问类变量,然而上述代码运行结果 如下:

4

in `new_method': uninitialized class variable @@v in OneClass (NameError)

如上,类实例变量可以访问,但类变量却不可以,WHY?

这是可能由于 class_eval 的作用域限制,事实上,不同 Ruby 版本,这个方法的结果都可能有差异。因此,在本例中,你可以使用 class_variable_get 来获取类变量,或者使用 打开类 的方法来访问类变量。

因为 class_eval 是使用的扁平作用域,所以 new_method 里 p @@v 其实是输出 class OneClass 的类变量,而类变量没有初始化就会报错。你要找 AnotherClass 的类变量就像楼上所说的通过过class_variable_get :@@v来查找

class variables are bound at compile-time

https://makandracards.com/makandra/14229-the-many-gotchas-of-ruby-class-variables

Class variables are bound at compile-time. Also note that only the class and module keywords can be used to change the scope to which class variables are bound. You can not change scope by using class_eval or instance_eval.

class variables 不同于其他变量,它们的含义更接近常量。OneClass 这个类中,并没有定义 @@v 这个变量,所以会提示 uninitialized class variable;一旦设定,就有值了

class OneClass
   @@v = 5
  def add_method_to aClass
    aClass.class_eval do
      def self.new_method  #定义AnotherClass类的一个类方法
        p @v
        p @@v
      end
    end
  end 
end

bianjp 回复

明白了 Thanks

cy1806152142 关闭了讨论。 02月26日 13:00
需要 登录 后方可回复, 如果你还没有账号请 注册新账号