Variável de instância de classe Ruby vs. variável de classe
as variáveis de classe são partilhadas por todos os objectos de uma classe, as variáveis de instância pertencem a um objecto. Não há muito espaço para usar variáveis de instância de classe se tivermos variáveis de classe.
Alguém pode explicar a diferença entre estes 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 S.s #15
p S.k #23
Já percebi, Turma. Variáveis de instância não são passadas ao longo da cadeia de herança!
5 answers
Instância variável numa 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]
Classe variável:
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 da classe) você pode armazenar algo comum para essa classe sem ter sub-classes automaticamente também obtê-los (e vice-versa). Com as variáveis de classe, você tem a conveniência de não ter que escrever self.class
a partir de um objeto de instância, e (quando desejável) Você também tem o compartilhamento automático em toda a hierarquia de classes.
Fusão estes em conjunto em um único exemplo que também cobre 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 depois em acçã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 no principal (apenas?) diferente é herança:
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
As variáveis de classe são partilhadas por todas as" instâncias de classe " (isto é, subclasses), enquanto as variáveis de instância de classe são específicas apenas a essa classe. Mas se você nunca pretende estender sua classe, A diferença é puramente acadêmica.
#as variáveis de instância de classe estão disponíveis apenas para o método de classe e não para métodos de instância, enquanto as variáveis de classe são aviláveis tanto para métodos de instância e métodos de classe. Também as variáveis de instância de classe são perdidas na cadeia de herança, enquanto as variáveis de classe 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 variáveis de classe são partilhadas entre uma dada classe e as suas subclasses. As variáveis de instância de classe pertencem a exatamente uma classe; suas subclasses são separadas.
Porque é que este comportamento existe? Bem, tudo em Ruby é um objeto-mesmo classes. Isso significa que cada classe tem um objeto da classeClass
(ou melhor, uma subclasse de Class
) correspondente a ela. (Quando você diz class Foo
, Você está realmente declarando uma constante Foo
e atribuindo um objeto de classe para ele.) E a cada O objeto Ruby pode ter variáveis de instância, então objetos de classe também podem ter variáveis de instância.
O problema é que as variáveis de instância nos objectos de classe não se comportam da forma que normalmente queres que as variáveis de classe se comportem. Você geralmente quer 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 tem seu próprio objeto de classe, e que objeto de classe tem suas próprias variáveis de instância. Então eles introduziram variáveis de classe separadas. com o comportamento que é mais provável que queiras.
Por outras palavras, as variáveis de instância de classe são uma espécie de acidente do design da Ruby. Não devias usá-los, a não ser que saibas que são o que procuras.Então como você sabe uma variável de classe são variáveis que estão disponíveis para uma classe específica e a sintaxe parece assim:
class myClass
@@teams = ["A's","Tigers"]
end
No entanto, raramente irá usar variáveis de classe em aplicações do mundo real porque pode realizar o mesmo através de variáveis locais ou de instância. Nada está errado se você usar variáveis de classe, mas não é comumente utilizado pela maioria dos desenvolvedores. Na verdade, as variáveis locais e de instância provavelmente compõem mais de 98 por cento das variáveis em seu aplicação, por isso é uma boa ideia estar familiarizado com eles.
Como o nome sugere, variáveis de instância estão disponíveis para uma instância específica. Existe uma sintaxe específica para definir variáveis de instância, você precisa usar o @ assinale 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
Neste código, você pode ver que existe uma variável de instância chamada @portfolio_ itens . Esta variável é criada no método índice e não é disponível para outros métodos no arquivo. Agora, por que eu não fiz isso apenas uma variável local uma vez que não está disponível para outros métodos na classe?
A razão para isto é porque os carris estão estruturados de tal forma que os ficheiros view e controller estão ligados para se comunicarem uns com os outros, por isso esta variável de instância @portfolio_item pode ser acedida no ficheiro associado view Assim:
<%= 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_ itens são disponível no singular para a página de visualização apenas porque eu fiz uma variável de instância no arquivo de controller.