Разница между переменными класса и переменными экземпляра класса? - PullRequest
89 голосов
/ 27 сентября 2010

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

Ответы [ 3 ]

148 голосов
/ 27 сентября 2010

Переменная класса (@@) является общей для класса и всех его потомков. Переменная экземпляра класса (@) не является общей для потомков класса.


Переменная класса (@@)

Давайте создадим класс Foo с переменной класса @@i и средствами доступа для чтения и записи @@i:

class Foo

  @@i = 1

  def self.i
    @@i
  end

  def self.i=(value)
    @@i = value
  end

end

И производный класс:

class Bar < Foo
end

Мы видим, что Foo и Bar имеют одинаковое значение для @@i:

p Foo.i    # => 1
p Bar.i    # => 1

И изменение @@i в одном изменяет его в обоих:

Bar.i = 2
p Foo.i    # => 2
p Bar.i    # => 2

Переменная экземпляра класса (@)

Давайте создадим простой класс с переменной экземпляра класса @i и средствами доступа для чтения и записи @i:

class Foo

  @i = 1

  def self.i
    @i
  end

  def self.i=(value)
    @i = value
  end

end

И производный класс:

class Bar < Foo
end

Мы видим, что хотя Bar наследует средства доступа для @i, он не наследует @i сам по себе:

p Foo.i    # => 1
p Bar.i    # => nil

Мы можем установить Бар @i, не влияя на Фу @i:

Bar.i = 2
p Foo.i    # => 1
p Bar.i    # => 2
69 голосов
/ 27 сентября 2010

Сначала вы должны понять, что классы тоже являются экземплярами - экземплярами класса Class.

Как только вы это поймете, вы сможете понять, что класс может иметь переменные экземпляра, связанные с ним, как обычные(читай: не класс) объект может.

Hello = Class.new

# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")

# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"

Обратите внимание, что переменная экземпляра в Hello полностью не связана и не отличается от переменной экземпляра в экземпляр из Hello

hello = Hello.new

# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")

# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")

# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"

Переменная класса , с другой стороны, является своего рода комбинацией двух вышеупомянутых, так как она доступна на самом Hello и его экземплярах, а также на подклассах.из Hello и их экземпляров:

HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new

Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"

Многие люди говорят, что следует избегать class variables из-за странного поведения, описанного выше, и рекомендуют использовать class instance variables вместо.

0 голосов
/ 15 января 2019

Также хочу добавить, что вы можете получить доступ к переменной класса (@@) из любого экземпляра класса

class Foo
  def set_name
    @@name = 'Nik'
  end

  def get_name
    @@name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik

Но вы не можете сделать то же самое для переменной экземпляра класса (@)

class Foo
  def set_name
    @name = 'Nik'
  end

  def get_name
    @name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil
...