Переменная экземпляра класса Ruby в сравнении с переменной класса

Я читал "Когда переменные экземпляра Ruby устанавливаются?" но я имею в виду, когда использовать переменные экземпляра класса.

Переменные класса разделяются всеми объектами класса, переменные экземпляра принадлежат одному объекту. Не осталось места, чтобы использовать переменные экземпляра класса, если у нас есть переменные класса.

Может ли кто-нибудь объяснить разницу между этими двумя и когда их использовать?

Вот пример кода:

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

Теперь я понимаю, переменные экземпляра класса не передаются по цепочке наследования!

Ответ 1

Переменная экземпляра в классе:

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 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]

С переменной экземпляра в классе (а не в экземпляре этого класса) вы можете сохранить что-то общее для этого класса, не получив их также подзапросами (и наоборот). С переменными класса вам удобнее не писать self.class из объекта экземпляра, и (при желании) вы также получаете автоматическое разделение по иерархии классов.


Объединяя их вместе в один пример, который также охватывает экземпляры экземпляров для экземпляров:

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

И затем в действии:

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] 

Ответ 2

Я считаю, что основным (только?) другим является наследование:

class T < S
end

p T.k
=> 23

S.k = 24
p T.k
=> 24

p T.s
=> nil

Переменные класса разделяются всеми "экземплярами класса" (например, подклассы), тогда как переменные экземпляра класса относятся только к этому классу. Но если вы никогда не намереваетесь расширить свой класс, разница будет чисто академической.

Ответ 3

Переменная экземпляра

#class доступна только для метода класса, а не для методов экземпляра, тогда как переменная класса доступна для методов экземпляра и методов класса. Кроме того, переменные экземпляра класса теряются в цепочке наследования, тогда как переменные класса не являются.

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

Ответ 4

Как говорили другие, переменные класса разделяются между данным классом и его подклассами. Переменные экземпляра класса относятся к одному классу; его подклассы являются отдельными.

Почему такое поведение существует? Ну, все в Ruby - это объект-четные классы. Это означает, что каждый класс имеет объект класса Class (вернее, подкласс Class), соответствующий ему. (Когда вы говорите class Foo, вы действительно объявляете константу Foo и присваиваете ему объект класса). И каждый объект Ruby может иметь переменные экземпляра, поэтому объекты класса также могут иметь переменные экземпляра.

Проблема в том, что переменные экземпляра в объектах класса действительно не ведут себя так, как обычно вы хотите, чтобы переменные класса вели себя. Обычно вам требуется, чтобы переменная класса, определенная в суперклассе, была разделена с ее подклассами, но это не так, как работают переменные экземпляра - подкласс имеет свой собственный объект класса, а этот объект класса имеет свои собственные переменные экземпляра. Таким образом, они ввели отдельные переменные класса с поведением, которое вы, скорее всего, захотите.

Другими словами, переменные экземпляра класса являются своего рода ошибкой дизайна Ruby. Вы, вероятно, не должны их использовать, если только вы не знаете, что они ищут.