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

Author: Community, 2013-04-03

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] 
 218
Author: Phrogz, 2017-01-27 18:45:10

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.

 30
Author: bioneuralnet, 2013-04-02 20:23:29

#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
 21
Author: Sachin Saxena, 2017-08-25 18:03:38

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 classe Class (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.
 12
Author: Brent Royal-Gordon, 2015-02-02 00:10:26

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.

 0
Author: Daniel, 2018-06-11 13:18:12