我读过When do Ruby instance variables get set?,但我对何时使用类示例变量有两种看法。
类变量由类的所有对象共享,示例变量属于一个对象。如果我们有类变量,就没有太多的空间来使用类示例变量。
有人能解释一下这两者的区别以及何时使用它们吗?
下面是一个代码示例:
class S
@@k = 23
@s = 15
def self.s
@s
end
def self.k
@@k
end
end
p S.s #15
p S.k #23
**更新:**我明白了!类示例变量不是沿着继承链传递的。
8条答案
按热度按时间ccrfmcuu1#
类上的示例变量:
类变量:
在类上使用示例变量(而不是在该类的示例上),你可以存储该类的一些公共内容,而不需要子类自动获取它们(反之亦然)。使用类变量,你不必从示例对象编写
self.class
,而且(如果需要的话)你还可以在整个类层次结构中自动共享。将这些合并到一个示例中,该示例还涵盖了示例上的示例变量:
然后在行动中:
xbp102n02#
来源
示例方法可用性
可继承性
9njqaruj3#
我认为主要的(唯一的?)不同是继承:
类变量由所有的“类示例”(即子类)共享,而类示例变量只特定于该类。但是如果你从来不打算扩展你的类,那么这种区别纯粹是学术上的。
93ze6v8z4#
正如其他人所说,类变量在给定的类和它的子类之间共享。它的子类是分开的。
为什么会存在这种行为呢?Ruby中的所有东西都是对象,甚至类也是。这意味着每个类都有一个类
Class
的对象(或者更确切地说,Class
的子类)。(当你说class Foo
时,你实际上是声明了一个常量Foo
,并将一个类对象赋给它。)每个Ruby对象都可以有示例变量,所以类对象也可以有示例变量。麻烦的是,类对象上的示例变量并不真正像你通常希望的那样表现。你通常希望在超类中定义的类变量与它的子类共享,但这不是示例变量的工作方式-子类有自己的类对象,而这个类对象有它自己的示例变量。所以他们引入了单独的类变量,它们的行为更可能是你想要的。
换句话说,类示例变量是Ruby设计的一个意外,除非你明确知道它们是你要找的,否则你可能不应该使用它们。
hrirmatl5#
Official Ruby FAQ: What is the difference between class variables and class instance variables?
主要的区别是关于继承的行为:类变量在一个类和它的所有子类之间共享,而类示例变量只属于一个特定的类。
在继承层次结构的上下文中,类变量在某种程度上可以被视为全局变量,具有全局变量带来的所有问题。例如,类变量可能(意外地)被其任何子类重新分配,影响所有其他类:
或者,一个祖先类可能会在以后被重新打开并更改,这可能会产生令人惊讶的效果:
所以,除非你确切地知道你在做什么,并且明确地需要这种行为,否则你最好使用类示例变量。
fumotvh36#
虽然使用类变量看起来很有用,但由于类变量在子类之间共享,并且它们可以在单例方法和示例方法中引用,因此存在一个显著的缺点。它们是共享的,因此子类可以更改类变量的值,并且基类也会受到更改的影响,这通常是不受欢迎的行为:
Rails引入了一个叫做class_attribute的方便方法。顾名思义,它声明了一个类级别的属性,其值可由子类继承。class_attribute值可以在单例和示例方法中访问,就像class变量一样。然而,Rails中class_attribute的巨大好处是子类可以更改自己的值,而不会影响父类。
gg0vcinb7#
对于那些有C背景的人,你可能会对与C等效的比较感兴趣:
正如我们所看到的,
k
是一个类似于static
的变量。这100%类似于一个全局变量,除了它由类 * 拥有 *(正确的是 scoped)。这使得更容易避免类似命名的变量之间的冲突。像任何全局变量一样,该变量只有一个示例,并且修改它总是可见的。另一方面,
s
是一个特定于对象的值。每个对象都有自己的值示例。在C++中,必须创建一个示例才能访问该变量。在Ruby中,类定义本身就是类的示例(在JavaScript中,这被称为原型),因此,您可以从类访问s
,而无需额外的示例化。类示例可以被修改,但是对s
的修改将是特定于每个示例(每个S
类型的对象)的。所以修改一个示例不会改变另一个示例的值。dxxyhpgq8#
简单示例展示
类变量的可继承性*
类示例变量的封装*
注意:使用
class << self
是一种方便,而不是必须在此块中的所有方法前面加上self.
注意:class << self
修改了self
,因此它指向Parent
的 * 元类 *(参见https://stackoverflow.com/a/38041660/960184)示例代码
ruby v3.0.2输出