Variável de instância de class Ruby vs. variável de class

Eu li ” Quando as variables ​​de instância Ruby são definidas? “, Mas tenho duas dúvidas quando usar variables ​​de instância de class.

As variables ​​de class são compartilhadas por todos os objects de uma class. As variables ​​de instância pertencem a um object. Não há muito espaço para usar variables ​​de instância de class se tivermos variables ​​de class.

Alguém poderia explicar a diferença entre esses dois e quando usá-los?

Aqui está um exemplo de código:

class S @@k = 23 @s = 15 def self.s @s end def self.k @@k end end p Ss #15 p Sk #23 

Eu entendo agora, as variables ​​de instância de class não são passadas ao longo da cadeia de inheritance!

   

Variável de instância em uma class:

 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 class:

 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 class (não em uma instância dessa class) você pode armazenar algo comum a essa class sem ter sub-classs automaticamente também obtê-las (e vice-versa). Com as variables ​​de class, você tem a conveniência de não ter que escrever self.class de um object de instância e (quando desejável) também obtém o compartilhamento automático em toda a hierarquia de classs.


Mesclando estes juntos em um único exemplo que também cobre variables ​​de instância em instâncias:

 class Parent @@family_things = [] # Shared between class and subclasss @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] 

Eu acredito que o principal (só?) Diferente é inheritance:

 class T < S end p Tk => 23 Sk = 24 p Tk => 24 p Ts => nil 

As variables ​​de class são compartilhadas por todas as “instâncias de class” (ou seja, subclasss), enquanto as variables ​​de instância de class são específicas para apenas essa class. Mas se você nunca pretende estender sua turma, a diferença é puramente acadêmica.

A variável de instância #class está disponível apenas para o método de class e não para os methods de instância, enquanto a variável de class é disponibilizada para os methods de instância e de class. Além disso, as variables ​​de instância de class são perdidas na cadeia de inheritance, enquanto as variables ​​de class não são.

 class Vars @class_ins_var = "class instance variable value" #class instance variable @@class_var = "class variable value" #class variable def self.class_method puts @class_ins_var puts @@class_var end def instance_method puts @class_ins_var puts @@class_var end end Vars.class_method puts "see the difference" obj = Vars.new obj.instance_method class VarsChild < Vars end VarsChild.class_method 

Como outros disseram, as variables ​​de class são compartilhadas entre uma determinada class e suas subclasss. Variáveis ​​de instância de class pertencem exatamente a uma class; suas subclasss são separadas.

Por que esse comportamento existe? Bem, tudo em Ruby é um object – até mesmo aulas. Isso significa que cada class tem um object da class Class (ou melhor, uma subclass de Class ) correspondente a ela. (Quando você diz class Foo , você está realmente declarando uma constante Foo e atribuindo um object de class a ela.) E todo object Ruby pode ter variables ​​de instância, então objects de class também podem ter variables ​​de instância.

O problema é que as variables ​​de instância em objects de class realmente não se comportam da maneira que você normalmente deseja que as variables ​​de class se comportem. Você geralmente deseja que uma variável de class definida em uma superclass seja compartilhada com suas subclasss, mas não é assim que as variables ​​de instância funcionam – a subclass tem seu próprio object de class e esse object de class tem suas próprias variables ​​de instância. Então eles introduziram variables ​​de class separadas com o comportamento que você está mais propenso a querer.

Em outras palavras, as variables ​​de instância de class são um tipo de acidente do design de Ruby. Você provavelmente não deve usá-los a menos que você saiba que eles são o que você está procurando.

Então, como você sabe, uma variável de class são variables ​​que estão disponíveis para uma class específica e a syntax se parece com isso:

 class myClass @@teams = ["A's","Tigers"] end 

No entanto, você raramente usará variables ​​de class em aplicativos do mundo real, pois poderá realizar o mesmo por meio de variables ​​locais ou de instância. Nada está errado se você usar variables ​​de class, mas não é comumente utilizado pela maioria dos desenvolvedores. Na verdade, as variables ​​locais e de instância provavelmente compõem mais de 98% das variables ​​em seu aplicativo, por isso é uma boa ideia estar familiarizado com elas.

Como o nome sugere, as variables ​​de instância estão disponíveis para uma instância específica. Existe uma syntax específica para definir variables ​​de instância, você precisa usar o sinal @ para definir uma variável. Aqui está um exemplo do mundo real do meu próprio trabalho:

 class PortfolioController < ApplicationController before_action :set_portfolio_item, only: [:edit, :update, :show, :destroy] layout 'portfolio' access all: [:show, :index, :angular], user: {except: [:destroy, :new, :create]} def index # this calls the model @portfolio_items = Portfolio.by_position end end 

Nesse código, você pode ver que existe uma variável de instância chamada @portfolio_items . Essa variável é criada no índice do método e não está disponível para outros methods no arquivo. Agora, por que eu não apenas fiz disso uma variável local, já que ela não está disponível para outros methods na class?

A razão para isso é que o Rails é estruturado de tal forma que os arquivos view e controller são conectados para se comunicarem entre si, portanto, essa variável de instância @portfolio_items pode ser acessada no arquivo de visão associado da seguinte forma:

 < %= form_for(@portfolio_item) do |f| %> < % if @portfolio_item.errors.any? %> < % @portfolio_item.errors.full_messages.each do |error| %> < % alert_generator error %> < % end %> < % end %> 

Agora, @portfolio_items estão disponíveis no singular apenas para a página de visualização porque criei uma variável de instância no arquivo do controlador.