Variável de instância em uma classe:
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]
Variável de classe:
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]
Com uma variável de instância em uma classe (não em uma instância dessa classe), você pode armazenar algo comum a essa classe sem que as subclasses também as obtenham automaticamente (e vice-versa). Com as variáveis de classe, você tem a conveniência de não precisar escrever self.class
de um objeto de instância e (quando desejável) também obtém compartilhamento automático em toda a hierarquia de classes.
Mesclando-os em um único exemplo que também abrange variáveis de instância em instâncias:
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
E então em ação:
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]
self.things
referenciou um métodothings
no escopo atual (no caso de uma instância de uma classe, será o método da instância), onde fazself.class.things
referência a umthings
método da classe de escopo atual (novamente no caso de uma instância de uma classe, isso significaria o método de classe).Eu acredito que o principal (apenas?) Diferente é a herança:
As variáveis de classe são compartilhadas por todas as "instâncias de classe" (ou seja, subclasses), enquanto as variáveis de instância de classe são específicas apenas para essa classe. Mas se você nunca pretende estender sua classe, a diferença é puramente acadêmica.
fonte
S.new.s => nil
eS.new.k => 23
.Fonte
Disponibilidade para métodos de instância
Herança
fonte
Como outros disseram, as variáveis de classe são compartilhadas entre uma determinada classe e suas subclasses. As variáveis de instância de classe pertencem a exatamente uma classe; suas subclasses são separadas.
Por que esse comportamento existe? Bem, tudo em Ruby é um objeto - até classes. Isso significa que cada classe tem um objeto da classe
Class
(ou melhor, uma subclasse deClass
) correspondente a ela. (Quando você dizclass Foo
, está realmente declarando uma constanteFoo
e atribuindo um objeto de classe a ela.) E todo objeto Ruby pode ter variáveis de instância, portanto, objetos de classe também podem ter variáveis de instância.O problema é que variáveis de instância em objetos de classe realmente não se comportam da maneira que você normalmente deseja que as variáveis de classe se comportem. Você geralmente deseja que uma variável de classe definida em uma superclasse seja compartilhada com suas subclasses, mas não é assim que as variáveis de instância funcionam - a subclasse possui seu próprio objeto de classe e esse objeto de classe possui suas próprias variáveis de instância. Então eles introduziram variáveis de classe separadas com o comportamento que você provavelmente deseja.
Em outras palavras, variáveis de instância de classe são como um acidente do design de Ruby. Você provavelmente não deve usá-los, a menos que saiba especificamente o que está procurando.
fonte
Perguntas frequentes oficiais sobre Ruby: Qual é a diferença entre variáveis de classe e variáveis de instância de classe?
A principal diferença é o comportamento referente à herança: as variáveis de classe são compartilhadas entre uma classe e todas as suas subclasses, enquanto as variáveis de instância de classe pertencem apenas a uma classe específica.
As variáveis de classe, de alguma forma, podem ser vistas como variáveis globais no contexto de uma hierarquia de herança, com todos os problemas que acompanham as variáveis globais. Por exemplo, uma variável de classe pode (acidentalmente) ser reatribuída por qualquer uma de suas subclasses, afetando todas as outras classes:
Ou então, uma classe ancestral pode ser reaberta e alterada posteriormente, com efeitos possivelmente surpreendentes:
Portanto, a menos que você saiba exatamente o que está fazendo e precise explicitamente desse tipo de comportamento, é melhor usar variáveis de instância de classe.
fonte
Para aqueles com experiência em C ++, talvez você esteja interessado em uma comparação com o equivalente em C ++:
Como podemos ver,
k
é umastatic
variável similar. Isso é 100% como uma variável global, exceto pelo fato de pertencer à classe (com o escopo definido como correto). Isso facilita evitar confrontos entre variáveis nomeadas de maneira semelhante. Como qualquer variável global, há apenas uma instância dessa variável e a modificação é sempre visível por todos.Por outro lado,
s
é um valor específico do objeto. Cada objeto tem sua própria instância do valor. No C ++, você deve criar uma instância para ter acesso a essa variável. No Ruby, a própria definição de classe é uma instância da classe (em JavaScript, isso é chamado de protótipo); portanto, você pode acessar as
partir da classe sem instanciação adicional. A instância da classe pode ser modificada, mas a modificação des
será específica para cada instância (cada objeto do tipoS
). Portanto, modificar um não mudará o valor em outro.fonte
Embora possa imediatamente parecer útil utilizar variáveis de instância de classe, como as variáveis de instância de classe são compartilhadas entre subclasses e podem ser referidas nos métodos singleton e de instância, há uma desvantagem significativa. Eles são compartilhados e, portanto, as subclasses podem alterar o valor da variável de instância da classe e a classe base também será afetada pela alteração, que geralmente é um comportamento indesejável:
O Rails apresenta um método útil chamado class_attribute. Como o nome indica, ele declara um atributo em nível de classe cujo valor é herdável por subclasses. O valor class_attribute pode ser acessado nos métodos singleton e de instância, como é o caso da variável de instância de classe. No entanto, o grande benefício com class_attribute no Rails é que as subclasses podem mudar seu próprio valor e não afetam a classe pai.
fonte
self.
sempre que quiser acessar o atributoc
, por exemploself.c
. Os documentos dizem que umdefault:
parâmetro pode ser passado,class_attribute
mas parece não funcionar devido ao ponto que acabei de mencionarself
.