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 @@i
e 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 @@i
em 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 @i
e 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 @i
si mesmo:
p Foo.i # => 1
p Bar.i # => nil
Podemos definir Bar @i
sem 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 Class
classe.
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 Hello
si mesma e às suas instâncias, bem como às subclasses de Hello
e 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 variables
por 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 #class
usos quando chamados em qualquer coisa, mas self
são cheiros de código embora. Você pode até mesmo dar um passo adiante e implementar acessadores de instância i
e i=
delegar para seus #class
equivalentes, 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.