Ruby类实例变量与类变量

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

“我读”https://stackoverflow.com/questions/826734/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
更新:我现在明白了!类实例变量不会沿着继承链传递。

我认为主要(仅?)不同之处在于继承:

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有什么区别?@cyborg
self.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";