晕菜了,Ruby类中的变量!

Posted 网络研发IT及工具装备部

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了晕菜了,Ruby类中的变量!相关的知识,希望对你有一定的参考价值。

最近研究 PACT for Ruby看一段开源代码时遇到了一个和Ruby类成员变量有关的问题。请看如下代码:

class AA
  @@member = "Hello,world"
    class << self
      attr_accessor :member    #
定义memberget/set 方法
    end
end
puts AA.member

问题是:这个 puts 会输出什么?

如果你回答是 Hello,World,那么恭喜你,你犯了和我一样的错误。实际上这条语句的输出是空,什么输出都没有。但是如果接着执行 

puts AA.class_variable_get(:@@member)

可以看到输出是 Hello,world

如果执行如下的代码:

AA.member = "Foo/Bar"
puts AA.member       #
结果是 Foo/Bar
puts AA.class_variable_get(:@@member)        #
结果还是 Hello,world


这就很让人抓狂了!


我们都知道类中如果某个变量用 @@前缀开始的话,那么它就是这个类的class_variable,这个类的所有实例都共享这一个变量;如果是用一个 @ 开始的话,那么它就是instance_variable,每一个类的实例都有自己的一份同名变量。

难道这里 class << self … end 里面通过 attr_accessor 定义的member属性,和外面的@@member不是同一个东西?事实确实如此,执行如下的代码:

pp AA.class_variables        #[:@@member]
pp AA.instance_variables     # [:@member]

可以看到,上面的代码确实是引入了两个变量,分别是@@member@member。因为在ruby里面,所有的一切都是对象,包括AA这个类本身,它也是一个对象,它是 Class 这个类的一个实例:-) 。所以,AA可以有他自己的 instance_variable。上面attr_accessor实际上为AA定义了它自己所特有的 instance_variable,名字叫做@member,这个变量是AA这个对象自己所独有,和@@member 毫无关系,也和AA这个类的所有实例毫无关系。

只要你愿意,你可以写如下的代码:

class AA
   @@member = "A class variable for AA, all instances of AA can use."
    @member = "A instance variable for AA only"
    class << self
        attr_accessor :member    #
定义对 member 成员的get/set 方法
    end
    attr_accessor :member    #
定义AA的实例变量
end
t = AA.new
t.member = "instance variable for AA's obj
t"
m = AA.new
m.member = "instance variable for AA's obj m"
这段代码里面,AA有一个叫@@member的类变量,对象t和m还各有一个叫 @member的实例变量,这两个实例变量相互独立;t 和 m还共享了AA的@@member这个类变量,在AA的instancemethod里面,可以直接读写这两个变量。


以上都很好理解。除此之外,AA这个Class的对象实例还有一个它自己所独有的实例变量@member。这个变量和 t、m两个对象没有关系,修改这个变量不会影响到 t.member;也就是说,下面的四个语句,访问的是四个完全不同的变量

pp t.member
pp m.member
pp t.class.member
pp t.class.class_variable_get(:@@member)

Ruby里面魔法太多,比如 class<<self 这种写法,就很容易把人给绕晕了,一般情况下,慎用。


以上是关于晕菜了,Ruby类中的变量!的主要内容,如果未能解决你的问题,请参考以下文章

Ruby入门1

Ruby中的符号和变量有什​​么区别? [复制]

ruby中的实例变量和类变量

python 类中的变量传递给类中的函数

如何从 Ruby 中的 CSV 标题行创建变量

如何将类名作为变量传递给ruby中的另一个类