Ruby类实例变量与类变量
“我读”https://stackoverflow.com/questions/826734/when-do-ruby-instance-variables-get-set“但我不知道何时使用类实例变量 类变量由一个类的所有对象共享,实例变量属于一个对象。如果我们有类变量,就没有多少空间可以使用类实例变量 有人能解释一下这两者的区别以及何时使用它们吗 下面是一个代码示例:Ruby类实例变量与类变量,ruby,instance-variables,class-variables,class-instance-variables,Ruby,Instance Variables,Class Variables,Class Instance Variables,“我读”https://stackoverflow.com/questions/826734/when-do-ruby-instance-variables-get-set“但我不知道何时使用类实例变量 类变量由一个类的所有对象共享,实例变量属于一个对象。如果我们有类变量,就没有多少空间可以使用类实例变量 有人能解释一下这两者的区别以及何时使用它们吗 下面是一个代码示例: class S @@k = 23 @s = 15 def self.s @s end def s
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
更新:我现在明白了!类实例变量不会沿着继承链传递。我认为主要(仅?)不同之处在于继承:
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
T类 23
S.k=24
p.T.k
=> 24
p.T.s
=>零
类变量由所有“类实例”(即子类)共享,而类实例变量仅特定于该类。但是,如果您从未打算扩展您的类,则差异纯粹是学术性的。类上的实例变量:
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]
然后在行动中:
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]
mama=Parent.new
papa=Parent.new
乔伊=孩子
suzy=Child.new
Parent.family_事物[汽车、搅拌机]
p Child.shared_things#=>[:拼图,:块]
乔伊:分享的东西[拼图,积木]
p suzy.shared#u things#=>[:拼图,:块]
爸爸,我的东西
妈妈,我的东西
p乔伊,我的东西[自行车]
p苏西我的东西[洋娃娃]
实例方法的可用性
- 类实例变量仅对类方法可用,而对实例方法不可用
- 实例方法和类方法都可以使用类变量
- 类实例变量在继承链中丢失
- 类变量不是
类变量
@class_ins_var=“class instance variable value”#class instance variable
@@class_var=“class variable value”#class variable
def self.class_方法
将@class_放入变量
放置@@class\u变量
结束
def实例法
将@class_放入变量
放置@@class\u变量
结束
结束
Vars.class_方法
将“看到差异”
obj=可变新
实例法
类VarsChild
正如其他人所说,类变量在给定类及其子类之间共享。类实例变量只属于一个类;它的子类是独立的
为什么会存在这种行为?Ruby中的所有东西都是对象,甚至是类。这意味着每个类都有一个与之对应的类class
(或者更确切地说,是class
的子类)的对象。(当你说class Foo
时,你实际上是在声明一个常量Foo
并给它分配一个类对象。)每个Ruby对象都可以有实例变量,因此类对象也可以有实例变量
问题是,类对象上的实例变量的行为与您通常希望的类变量的行为方式不同。您通常希望在超类中定义的类变量与其子类共享,但实例变量不是这样工作的子类有自己的类对象,而该类对象有自己的实例变量。因此,他们引入了单独的类变量,这些变量具有您更可能想要的行为
换句话说,类实例变量在某种程度上是Ruby设计中的意外事件。除非您明确知道它们是您要寻找的对象,否则您可能不应该使用它们。虽然使用类变量似乎很有用,但由于类变量在子类之间共享,并且它们可以在单例和实例方法中引用,因此有一个单独的缺点。它们是共享的,因此子类可以更改类变量的值,基类也会受到更改的影响,这通常是不受欢迎的行为:
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"
C类
@@c='c'
def self.cval
@@c
结束
结束
C.C_val
=>“c”
D类:更改值
D.改变
(irb):12:警告:从顶层访问类变量
=>“d”
C.C_val
=>“d”
Rails引入了一个名为class_attribute的简便方法。顾名思义,它声明了一个类级属性,其值可由子类继承。class_属性值可以在singleton和instance方法中访问,就像class变量一样。然而,Rails中class_属性的巨大好处是子类可以改变自己的值,并且不会影响父类
class C
class_attribute :c
self.c = 'c'
end
C.c
=> "c"
class D < C
end
D.c = 'd'
=> "d"
C.c
=> "c"
C类
类属性:c
self.c='c'
结束
C.C
=>“c”
D类“d”
C.C
=>“c”
主要区别在于继承行为:类变量在类及其所有子类之间共享,而类实例变量只属于一个特定类
类变量在某种程度上可以被视为继承层次结构上下文中的全局变量,以及全局变量带来的所有问题。例如,类变量可能(意外地)被其任何子类重新分配,从而影响所有其他类:
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" (!)
这样,除非你完全知道你在做什么,并且明确需要这种行为,你最好使用类实例变量。
< P>对于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";
S类
{
private://这并不完全正确,在Ruby中,您仍然可以访问这些
静态int k=23;
int s=15;
公众:
int get_s(){return s;}
静态int get_k(){return k;}
};
std::cerr so class变量就像Java中的静态变量一样?@Phronz self.things和你在代码中提到的self.class.things有什么区别?@cyborgself.things
引用了当前sco中的一个方法things
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" (!)
class Foo
@@var = "foo"
def self.var
@@var
end
end
Foo.var # => "foo" (as expected)
class Object
@@var = "object"
end
Foo.var # => "object" (!)
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";