晕菜了,Ruby类中的变量!
Posted 网络研发IT及工具装备部
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了晕菜了,Ruby类中的变量!相关的知识,希望对你有一定的参考价值。
最近研究 PACT for Ruby,看一段开源代码时遇到了一个和Ruby类成员变量有关的问题。请看如下代码:
class AA
@@member = "Hello,world"
class << self
attr_accessor :member #定义member的get/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类中的变量!的主要内容,如果未能解决你的问题,请参考以下文章