Respostas:
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
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.
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
Foo.i, mas como você pode fazer o mesmo para todas as instâncias dessa classe Foo.new.i?
#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.