Diferença entre variáveis ​​de classe e variáveis ​​de instância de classe?


Respostas:


151

Uma variável de classe ( @@) é compartilhada entre a classe e todos os seus descendentes. Uma variável de instância de classe ( @) não é compartilhada pelos descendentes da classe.


Variável de classe ( @@)

Vamos ter uma classe Foo com uma variável de classe @@ie acessadores para leitura e escrita @@i:

class Foo

  @@i = 1

  def self.i
    @@i
  end

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

end

E uma classe derivada:

class Bar < Foo
end

Vemos que Foo e Bar têm o mesmo valor para @@i:

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

E mudar @@iem um muda em ambos:

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

Variável de instância de classe ( @)

Vamos fazer uma classe simples com uma variável de instância de classe @ie acessadores para leitura e escrita @i:

class Foo

  @i = 1

  def self.i
    @i
  end

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

end

E uma classe derivada:

class Bar < Foo
end

Vemos que, embora Bar herde os acessadores de @i, ele não herda a @isi mesmo:

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

Podemos definir Bar @isem afetar Foo @i:

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

1
Por que retornar variáveis ​​de instância usando métodos de classe? Você costuma se deparar com essa situação?
sekmo

1
@sekmo Os acessadores nesses exemplos retornam variáveis ​​de instância de classe , que pertencem à classe, ou variáveis ​​de classe , que pertencem à hierarquia de classes. Eles não retornam variáveis ​​de instância simples que pertencem a instâncias da classe. Os termos "variável de instância", "varaible de instância de classe" e "variável de classe" são bastante confusos, não são?
Wayne Conrad

72

Primeiro você deve entender que as classes também são instâncias - instâncias da Classclasse.

Depois de entender isso, você pode entender que uma classe pode ter variáveis ​​de instância associadas a ela, assim como um objeto normal (leia-se: não classe) pode.

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!"

Observe que uma variável de instância em Helloé completamente não relacionada e distinta de uma variável de instância em uma instância deHello

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!"

Uma variável de classe, por outro lado, é uma espécie de combinação das duas anteriores, pois é acessível a Hellosi mesma e às suas instâncias, bem como às subclasses de Helloe suas instâncias:

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!"

Muitas pessoas dizem para evitar class variablespor causa do comportamento estranho acima e recomendam o uso de class instance variables.


2
+1 Super Explicação! Isso é algo que todo programador novo em Ruby deve digerir.
TomZ

0

Também quero acrescentar que você pode obter acesso à variável de classe ( @@) a partir de qualquer instância da classe

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

Mas você não pode fazer o mesmo para a variável de instância de classe ( @)

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

-1: Incorreto: as variáveis ​​de instância de classe podem ser acessadas de todas as instâncias dessa classe (desde que os acessadores estejam presentes). Além disso, seu exemplo mostra variáveis ​​de instância regulares, não variáveis ​​de instância de classe. Variáveis ​​de instância de classe são declaradas fora dos métodos e são fundamentalmente diferentes de variáveis ​​de instância regulares e variáveis ​​de classe.
The Pellmeister

Como você pode obter acesso às variáveis ​​de instância de classe de cada instância dessa classe?
Evan Ross

Você leu a resposta de Wayne Conrad? Isso literalmente explica tudo. stackoverflow.com/a/3803089/439592
The Pellmeister

Eu sei que você pode obter acesso de métodos de classe como Foo.i, mas como você pode fazer o mesmo para todas as instâncias dessa classe Foo.new.i?
Evan Ross

Usando #class. Eu pessoalmente acho que os #classusos quando chamados em qualquer coisa, mas selfsão cheiros de código embora. Você pode até mesmo dar um passo adiante e implementar acessadores de instância ie i=delegar para seus #classequivalentes, caso em que você pode fazer Foo.new.i. Não recomendo fazer isso, pois cria uma interface confusa, sugerindo que você está modificando um membro do objeto.
The Pellmeister
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.