Ruby 类变量存在于对象里还是类中

anleb · 2012年07月26日 · 最后由 zw963 回复于 2012年07月28日 · 4521 次阅读

根据元编程,对象中有 4 个东西:引用 实例变量 object_id 状态,方法存在于类中,这样才可以共享实例方法,难道类变量也存在与类中吗?

这个问题我也答不上,类本身也是对象,所以类变量还是存在对象中的,但是具体我并不能确定,刚才想了一下,感觉“类变量”这个设计似乎有些多余

用 class_eval 可以访问到,逻辑上是在类中。 当然几乎每一本 Ruby 教材都不提倡用这个

#2 楼 @jjym 你记反了吧,是不提倡用全局变量

#1 楼 @fsword 是这样的,对象的所拥有的类变量,是存在 对象所在类中的,因为这样类变量才可以共享。你说的 类本身也是对象,是对的,但是 当类本身是对象的时候,他的类变量就存在于 Class 中

类变量作用类似 Java 的静态变量。 能够为该类对象以及子类对象访问,不可控风险较大。特别是在顶级对象上下文中(名称为 Main 的 Object 对象)下定义类变量,几乎所有对象都能访问该类变量。的确不太推荐使用,

#5 楼 @tech_blogbin

嗨,首先你的回复,根本不是楼主讨论的问题。其次,你的回复也是错的。前言不大后语,你那些演示代码,从头到尾,都在演示类实例变量,根本没有类变量的影子。他们谈的类变量是@@类变量。

#4 楼 @Anleb 我发现大家都一样。从一开始,我就在思考类变量到底在那里,也没有个确定的结果,双飞燕上也没有介绍,我不赞成你的理解,类对象是 Class 的实例,你如果说类变量存在于 Class 中,那么即使存在继承关系的两个类,不可能在子类中修改父类的类变量。你说的那个东西,应该是类的实例变量才是。

@@类变量,我的理解,他就是类对象指向的那个堆中 (定义了实例方法的那一片内存区域) 的一个特殊的变量而已。你就可以理解为一个整个继承体系内的一个全局变量 就是了,反正应该是个特殊的 dd, 我也无法确定到底是如何实现的。只要知道怎么用就行了。

实现方式,存储在 klass 的 iv_tbl 中:

1508  VALUE
1509  rb_cvar_get(klass, id)
1510      VALUE klass;
1511      ID id;
1512  {
1513      VALUE value;
1514      VALUE tmp;
1515
1516      tmp = klass;
1517      while (tmp) {
1518          if (RCLASS(tmp)->iv_tbl) {
1519              if (st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
1520                  if (RTEST(ruby_verbose)) {
1521                      cvar_override_check(id, tmp);
1522                  }
1523                  return value;
1524              }
1525          }
1526          tmp = RCLASS(tmp)->super;
1527      }
1528
1529      rb_name_error(id,"uninitialized class variable %s in %s",
1530                    rb_id2name(id), rb_class2name(klass));
1531      return Qnil;                /* not reached */
1532  }

(variable.c)

参考:http://thinkinginruby.group.iteye.com/

#6 楼 @zw963 你可能没理解我的意思,首先确定的是类的对象的实例变量是在对象里的,类本身也是对象,所以我们统称为对象的实例变量,ok,我上面的问题是类变量,这个东西,可以让任何所属这个类的对象访问,和实例方法一样,所以是应该在类中的,总结: 对象中有:实例变量 (属于某个对象的) id 类的引用 状态 类中有:实例方法 (属于所有对象的) 类变量 (属于所有对象的) 实例变量 (属于这个类的) Class 中有:实例方法 (属于上面某个类的) 依次这样下去

#6 楼 @zw963 多谢提醒!之前的代码的确是错的。

#8 楼 @Anleb

咋俩想的其实就是一样的。
不过你最后把 Class 单独分出来,没必要。Class.class 也是 Class.

#10 楼 @zw963 你有 QQ 啥吗,我看你也是学习狂,我们交流下,我今天有个问题,我发你连接http://ruby-china.org/topics/4588

#11 楼 @Anleb

哈。你这样形容我,还加了个也.... 你有 skype 吗?加我 vil963

#12 楼 @zw963 这个问题似乎有点纠结,如果你们讨论有结果,不妨再发回来 #7 楼 @lyfi2003 源码能说明目前的做法,不过为什么要这么设计呢?

#13 楼 @fsword

我觉得就是为了要实现这个怪怪的功能而设计。牵一发而动全身,整个类中只有一份共享,这就是类变量的目的。既然 Matz 一定要搞这么个东西出来,自然有特殊的场合,类变量是无法替代的。

这是类型系统的基本问题啊。

  • object is-a type
  • type is-a object

至少可以追溯到 Simula-67。

#15 楼 @bhuztez

其实我了解楼主还有@fsword的想法,他们 (包括我) 都是属于被 Ruby 洗脑了。凡事儿都要使用对象这个概念解释一番。这在 Ruby 语言之上是没错的。不过非要把这个想法加到 Ruby 的实现上,就会是这样。之前我也曾经用对象的思维方式来考虑方法的定义呢。不过很显然,脑子想破也想不通的。

@fsword 类变量自然属于类,类中的 iv_tble 存放类变量正好。另一种实现可以采用全局表,但全局表查询会存在问题,也不符合设计模式中全局变量的使用。

#16 楼 @zw963 这个是概念上的,无论你怎么实现,你都是要实现这个的。

object 可以有成员变量,因为 type is-a object,当然可以有成员变量了。

#18 楼 @bhuztez

你讲的这个 type is-a object 理论,是你说的那个 Simula-67 里面的吗?

你说的这个成员变量和类变量是两码事吧,我觉得按照你的想法,其实是指的类应该有类的实例变量.

#19 楼 @zw963

你讲的这个 type is-a object 理论,是你说的那个 Simula-67 里面的吗?

自那以后,有类型系统的语言,类型系统一般来说都是这么设计的。

首先要定义两个特殊的东西,object, type ,接着定义 is-a

因为,* is-a object,于是

  • object is-a object
  • type is-a object

又,A is-a B => B is-a type,所以

  • object is-a type
  • type is-a type

你说的这个成员变量和类变量是两码事吧,我觉得按照你的想法,其实是指的类应该有类的实例变量.

你把类给特殊化了。从上面的定义出发,你所以为的类变量,就是一个普通的成员变量,无非这个object恰好是一个类而已。

P.S. 在这里不区分classtypeinstanceobject

#20 楼 @bhuztez

看你介绍,看得晕晕乎乎,不过觉得很有意思。

又,typeof(Anything) is-a type,所以

type is-a type object is-a type

我怎么觉得应该是

又,typeof(Anything) is-a type,所以

typeof(type) is-a type typeof(object) is-a type

或者:

因此,typeof(Anything) is-a object,所以

type is-a object.

而,object is-a type, 这应该是在特殊情况下,才满足。

你把类给特殊化了。根据定义,类,就是一个普通的 object。你所以为的类变量,只不过就是一个成员变量,无非这个 object 恰好是一个类而已. P.S. 在这里不区分 class 和 type,instance 和 object

你讲的这个成员变量到底是什么东西?我怎么觉得这个概念非常像 C++ 里面的说法。C++ 里面的成员变量的确是在类当中被定义的。其实咱们谈的那个@@类变量, 其实的确和你说的成员变量挺像的。不过我现在想确认一点,在 C++ 中,一个类的两个不同实例,他们的成员变量彼此之间有影响吗?我记得好像沒有影响,即,C++中, 每个类的实例都有自己单独的成员变量值., 如果是这样的话,咱们谈的还不是一个东西。

你说的成员变量只是一个相对于 Ruby 的类实例变量不同定义方式而已。而这里谈的类变量, 他就是类自己的变量。所有的子孙共享同一个变量,整个继承体系只有这么一个,而且这个变量只在定义类变量的那个类中存在唯一的一份拷贝。

#21 楼 @zw963

你讲的这个成员变量到底是什么东西?

成员变量:instance.member

但 Ruby 的语法导致这里很复杂。因为 Ruby 里调用一个函数,不需要括号。这导致了instance.X实际上就是instance.X()。所以必须引入@X这种方式去取得成员变量。

在 C++ 中,一个类的两个不同实例,他们的成员变量彼此之间有影响吗

你忘了加了static之后,就变成类的成员变量,而不是实例的成员变量。

#21 楼 @zw963

我怎么觉得应该是

又,typeof(Anything) is-a type,所以

typeof(type) is-a type
typeof(object) is-a type

我改一下,现在应该清楚一点了。

有 Bug 啊,@X也被替换掉了

#22 楼 @bhuztez

嗯。现在看起来清楚了。呵呵。牛啊,这花花肠子绕的。

我的确忘记有 static 这回事儿了。那就没错了,Ruby 中的类变量,就是 C++ 中加 static 的成员变量。

跑题一下:

类变量类的实例变量是有区别的。

1.类的实例变量就和普通变量一样,存在对象里。只不过这个类是 Class,因为所有的类都是 Class 的实例。这就是 Ruby 里说的一切都是对象。

2.类变量我的理解是:类范围内的全局变量,他可以被实例和类本身访问/修改,可以被继承。

#22 楼 @bhuztez

有关引入@成员变量,我记得当时学 Ruby 时还是有心得的。主要原因是 Ruby 无法区分这是一个变量还是一个方法调用,我倒是觉得引入了@实例变量,让编写一个类,变的更直观,更简单。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号