Ruby 类实例变量与类变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15773552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby class instance variable vs. class variable
提问by Elmor
I read "When do Ruby instance variables get set?" but I'm of two minds when to use class instance variables.
我读过“什么时候设置 Ruby 实例变量?”但是我有两种想法,什么时候使用类实例变量。
Class variables are shared by all objects of a class, Instance variables belong to one object. There's not much room left to use class instance variables if we have class variables.
类变量由一个类的所有对象共享,实例变量属于一个对象。如果我们有类变量,就没有多少空间可以使用类实例变量了。
Could someone explain the difference between these two and when to use them?
有人可以解释这两者之间的区别以及何时使用它们吗?
Here's a code example:
这是一个代码示例:
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
I understand now, Class Instance Variables are not passed along the inheritance chain!
我现在明白了,类实例变量不是沿着继承链传递的!
回答by Phrogz
Instance variable on a class:
类上的实例变量:
class Parent
@things = []
def self.things
@things
end
def things
self.class.things
end
end
class Child < Parent
@things = []
end
Parent.things << :car
Child.things << :doll
mom = Parent.new
dad = Parent.new
p Parent.things #=> [:car]
p Child.things #=> [:doll]
p mom.things #=> [:car]
p dad.things #=> [:car]
Class variable:
类变量:
class Parent
@@things = []
def self.things
@@things
end
def things
@@things
end
end
class Child < Parent
end
Parent.things << :car
Child.things << :doll
p Parent.things #=> [:car,:doll]
p Child.things #=> [:car,:doll]
mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new
[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
With an instance variable on a class (not on an instance of that class) you can store something common to that class without having sub-classes automatically also get them (and vice-versa). With class variables, you have the convenience of not having to write self.classfrom an instance object, and (when desirable) you also get automatic sharing throughout the class hierarchy.
使用类上的实例变量(而不是该类的实例),您可以存储该类的通用内容,而无需子类也自动获取它们(反之亦然)。使用类变量,您可以方便地不必self.class从实例对象写入,并且(在需要时)您还可以在整个类层次结构中自动共享。
Merging these together into a single example that also covers instance variables on instances:
将这些合并到一个示例中,该示例还涵盖了实例上的实例变量:
class Parent
@@family_things = [] # Shared between class and subclasses
@shared_things = [] # Specific to this class
def self.family_things
@@family_things
end
def self.shared_things
@shared_things
end
attr_accessor :my_things
def initialize
@my_things = [] # Just for me
end
def family_things
self.class.family_things
end
def shared_things
self.class.shared_things
end
end
class Child < Parent
@shared_things = []
end
And then in action:
然后在行动:
mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new
Parent.family_things << :house
papa.family_things << :vacuum
mama.shared_things << :car
papa.shared_things << :blender
papa.my_things << :quadcopter
joey.my_things << :bike
suzy.my_things << :doll
joey.shared_things << :puzzle
suzy.shared_things << :blocks
p Parent.family_things #=> [:house, :vacuum]
p Child.family_things #=> [:house, :vacuum]
p papa.family_things #=> [:house, :vacuum]
p mama.family_things #=> [:house, :vacuum]
p joey.family_things #=> [:house, :vacuum]
p suzy.family_things #=> [:house, :vacuum]
p Parent.shared_things #=> [:car, :blender]
p papa.shared_things #=> [:car, :blender]
p mama.shared_things #=> [:car, :blender]
p Child.shared_things #=> [:puzzle, :blocks]
p joey.shared_things #=> [:puzzle, :blocks]
p suzy.shared_things #=> [:puzzle, :blocks]
p papa.my_things #=> [:quadcopter]
p mama.my_things #=> []
p joey.my_things #=> [:bike]
p suzy.my_things #=> [:doll]
回答by bioneuralnet
I believe the main (only?) different is inheritance:
我相信主要(唯一?)不同的是继承:
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
Class variables are shared by all "class instances" (i.e. subclasses), whereas class instance variables are specific to only that class. But if you never intend to extend your class, the difference is purely academic.
类变量由所有“类实例”(即子类)共享,而类实例变量仅特定于该类。但是,如果您从不打算扩展课程,那么区别纯粹是学术上的。
回答by Sachin Saxena
Availability to instance methods
实例方法的可用性
- Class instance variables are available only to class methods and not to instance methods.
- Class variables are available to both instance methods and class methods.
- 类实例变量只对类方法可用,对实例方法不可用。
- 类变量可用于实例方法和类方法。
Inheritability
可继承性
- Class instance variables are lost in the inheritance chain.
- Class variables are not.
- 类实例变量在继承链中丢失。
- 类变量不是。
class Vars
@class_ins_var = "class instance variable value" #class instance variable
@@class_var = "class variable value" #class variable
def self.class_method
puts @class_ins_var
puts @@class_var
end
def instance_method
puts @class_ins_var
puts @@class_var
end
end
Vars.class_method
puts "see the difference"
obj = Vars.new
obj.instance_method
class VarsChild < Vars
end
VarsChild.class_method
回答by Brent Royal-Gordon
As others said, class variables are shared between a given class and its subclasses. Class instance variables belong to exactly one class; its subclasses are separate.
正如其他人所说,类变量在给定类及其子类之间共享。类实例变量只属于一个类;它的子类是分开的。
Why does this behavior exist? Well, everything in Ruby is an object—even classes. That means that each class has an object of the class Class(or rather, a subclass of Class) corresponding to it. (When you say class Foo, you're really declaring a constant Fooand assigning a class object to it.) And every Ruby object can have instance variables, so class objects can have instance variables, too.
为什么会存在这种行为?好吧,Ruby 中的一切都是对象——甚至是类。这意味着每个类都有一个对应于它的类的对象Class(或者更确切地说,是 的子类Class)。(当您说 时class Foo,您实际上是在声明一个常量Foo并为其分配一个类对象。)而且每个 Ruby 对象都可以有实例变量,因此类对象也可以有实例变量。
The trouble is, instance variables on class objects don't really behave the way you usually want class variables to behave. You usually want a class variable defined in a superclass to be shared with its subclasses, but that's not how instance variables work—the subclass has its own class object, and that class object has its own instance variables. So they introduced separate class variables with the behavior you're more likely to want.
问题是,类对象上的实例变量的行为方式与您通常希望类变量的行为方式不同。您通常希望在超类中定义的类变量与其子类共享,但这不是实例变量的工作方式——子类有自己的类对象,而类对象有自己的实例变量。因此,他们引入了具有您更可能想要的行为的单独类变量。
In other words, class instance variables are sort of an accident of Ruby's design. You probably shouldn't use them unless you specifically know they're what you're looking for.
换句话说,类实例变量是 Ruby 设计的一个意外。您可能不应该使用它们,除非您明确知道它们是您要寻找的东西。
回答by Donato
While it may immediately seem useful to utilize class instance variables, since class instance variable are shared among subclasses and they can be referred to within both singleton and instance methods, there is a singificant drawback. They are shared and so subclasses can change the value of the class instance variable, and the base class will also be affected by the change, which is usually undesirable behavior:
虽然使用类实例变量可能立即看起来很有用,但由于类实例变量在子类之间共享,并且它们可以在单例方法和实例方法中引用,但存在一个明显的缺点。它们是共享的,因此子类可以更改类实例变量的值,而基类也会受到更改的影响,这通常是不受欢迎的行为:
class C
@@c = 'c'
def self.c_val
@@c
end
end
C.c_val
=> "c"
class D < C
end
D.instance_eval do
def change_c_val
@@c = 'd'
end
end
=> :change_c_val
D.change_c_val
(irb):12: warning: class variable access from toplevel
=> "d"
C.c_val
=> "d"
Rails introduces a handy method called class_attribute. As the name implies, it declares a class-level attribute whose value is inheritable by subclasses. The class_attribute value can be accessed in both singleton and instance methods, as is the case with the class instance variable. However, the huge benefit with class_attribute in Rails is subclasses can change their own value and it will not impact parent class.
Rails 引入了一个方便的方法,称为 class_attribute。顾名思义,它声明了一个类级别的属性,其值可由子类继承。class_attribute 值可以在单例方法和实例方法中访问,就像使用类实例变量一样。但是,Rails 中 class_attribute 的巨大好处是子类可以更改自己的值,并且不会影响父类。
class C
class_attribute :c
self.c = 'c'
end
C.c
=> "c"
class D < C
end
D.c = 'd'
=> "d"
C.c
=> "c"
回答by notapatch
Official Ruby FAQ: What is the difference between class variables and class instance variables?
The main difference is the behavior concerning inheritance: class variables are shared between a class and all its subclasses, while class instance variables only belong to one specific class.
主要区别在于关于继承的行为:类变量在一个类及其所有子类之间共享,而类实例变量只属于一个特定的类。
Class variables in some way can be seen as global variables within the context of an inheritance hierarchy, with all the problems that come with global variables. For instance, a class variable might (accidentally) be reassigned by any of its subclasses, affecting all other classes:
类变量在某种程度上可以被视为继承层次结构上下文中的全局变量,具有全局变量带来的所有问题。例如,一个类变量可能(意外地)被它的任何子类重新分配,影响所有其他类:
class Woof
@@sound = "woof"
def self.sound
@@sound
end
end
Woof.sound # => "woof"
class LoudWoof < Woof
@@sound = "WOOF"
end
LoudWoof.sound # => "WOOF"
Woof.sound # => "WOOF" (!)
Or, an ancestor class might later be reopened and changed, with possibly surprising effects:
或者,以后可能会重新打开和更改祖先类,这可能会产生令人惊讶的效果:
class Foo
@@var = "foo"
def self.var
@@var
end
end
Foo.var # => "foo" (as expected)
class Object
@@var = "object"
end
Foo.var # => "object" (!)
So, unless you exactly know what you are doing and explicitly need this kind of behavior, you better should use class instance variables.
因此,除非您确切地知道自己在做什么并且明确需要这种行为,否则最好使用类实例变量。
回答by Alexis Wilke
For those with a C++ background, you may be interested in a comparison with the C++ equivalent:
对于具有 C++ 背景的人,您可能对与 C++ 等效项进行比较感兴趣:
class S
{
private: // this is not quite true, in Ruby you can still access these
static int k = 23;
int s = 15;
public:
int get_s() { return s; }
static int get_k() { return k; }
};
std::cerr << S::k() << "\n";
S instance;
std::cerr << instance.s() << "\n";
std::cerr << instance.k() << "\n";
As we can see, kis a staticlike variable. This is 100% like a global variable, except that it's ownedby the class (scopedto be correct). This makes it easier to avoid clashes between similarly named variables. Like any global variable, there is just one instance of that variable and modifying it is always visible by all.
正如我们所见,k是一个staticlike变量。这是100%像一个全局变量,不同之处在于它拥有由类(作用域是正确的)。这使得更容易避免类似命名的变量之间的冲突。与任何全局变量一样,该变量只有一个实例,并且对其进行修改始终对所有人可见。
On the other hand, sis an object specific value. Each object has its own instance of the value. In C++, you must create an instance to have access to that variable. In Ruby, the class definition is itself an instance of the class (in JavaScript, this is called a prototype), therefore you can access sfrom the class without additional instantiation. The class instance can be modified, but modification of sis going to be specific to each instance (each object of type S). So modifying one will not change the value in another.
另一方面,s是对象特定的值。每个对象都有自己的值实例。在 C++ 中,您必须创建一个实例才能访问该变量。在 Ruby 中,类定义本身就是类的一个实例(在 JavaScript 中,这称为原型),因此您可以s从类中访问,而无需额外的实例化。类实例可以修改,但修改s将特定于每个实例(每个类型的对象S)。所以修改一个不会改变另一个的值。

