Ruby variable d'instance de classe contre classe variable

j'ai lu " quand les variables d'instance de Ruby sont-elles définies? " mais je suis de deux esprits quand utiliser des variables d'instance de classe.

Les variables de classe

sont partagées par tous les objets d'une classe, les variables D'Instance appartiennent à un objet. Il n'y a plus beaucoup de place pour utiliser des variables d'instance de classe si nous avons des variables de classe.

quelqu'un Pourrait-il expliquer la différence entre ces deux et quand les utiliser?

Voici un exemple de code:

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

je comprends maintenant, les Variables D'Instance de classe ne sont pas passées le long de la chaîne d'héritage!

152
demandé sur Community 2013-04-03 00:17:00

5 réponses

variable D'Instance sur une 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]

variable 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]

avec une variable d'instance sur une classe (et non sur une instance de cette classe) vous pouvez stocker quelque chose de commun à cette classe sans avoir de sous-classes automatiquement aussi les obtenir (et vice-versa). Avec les variables de classe, vous avez la commodité de ne pas avoir à écrire self.class à partir d'un objet d'instance, et (lorsque cela est souhaitable) vous obtenez également le partage automatique tout au long de la hiérarchie de classe.


les fusionnant en un seul exemple qui couvre également les variables d'instance sur les instances:

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

et puis en action:

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
répondu Phrogz 2017-01-27 18:45:10

je crois que la principale (seule?) l'héritage est différent:

class T < S
end

p T.k
=> 23

S.k = 24
p T.k
=> 24

p T.s
=> nil
Les variables de classe

sont partagées par toutes les" instances de classe " (c'est-à-dire les sous-classes), alors que les variables d'instance de classe sont spécifiques à cette classe seulement. Mais si vous n'avez jamais l'intention de prolonger votre classe, la différence est purement académique.

30
répondu bioneuralnet 2013-04-02 20:23:29

#variable d'instance de classe sont disponibles uniquement à la méthode de la classe et de ne pas les méthodes d'instance alors que variable de classe sont disponibles à la fois les méthodes d'instance et les méthodes de la classe. De même, les variables d'instance de classe sont perdues dans la chaîne de transmission alors que les variables de classe ne le sont pas.

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
répondu Sachin Saxena 2017-08-25 18:03:38

comme d'autres l'ont dit, les variables de classe sont partagées entre une classe donnée et ses sous-classes. Les variables d'instance de classe appartiennent à exactement une classe; ses sous-classes sont séparées.

Pourquoi ce problème existe? Tout à Ruby est un objet, même les cours. Cela signifie que chaque classe a un objet de la classe Class (ou plutôt, une sous-classe de Class ) correspondant. (Quand vous dites class Foo , vous déclarez vraiment une constante Foo et lui assigner un objet de classe.) Et chaque objet Ruby peut avoir des variables d'instance, donc les objets de classe peuvent aussi avoir des variables d'instance.

le problème est, les variables d'instance sur les objets de classe ne se comportent pas vraiment de la façon dont vous voulez généralement que les variables de classe se comportent. Vous voulez habituellement qu'une variable de classe définie dans une superclasse soit partagée avec ses sous-classes, mais ce n'est pas comme cela que les variables d'instance fonctionnent-la sous-classe a son propre objet de classe, et cet objet de classe a son propre les variables d'instance. Donc ils ont introduit des variables de classe séparées avec le comportement que vous êtes plus susceptible de vouloir.

en d'autres termes, les variables d'instance de classe sont une sorte d'accident de la conception de Ruby. Vous ne devriez probablement pas les utiliser à moins que vous sachiez spécifiquement qu'ils sont ce que vous cherchez.

12
répondu Brent Royal-Gordon 2015-02-02 00:10:26

comme vous le savez une variable de classe sont des variables qui sont disponibles pour une classe spécifique et la syntaxe ressemble ainsi:

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

cependant, vous utiliserez rarement des variables de classe dans des applications réelles parce que vous pouvez accomplir la même chose à travers des variables locales ou d'instance. Rien n'est mauvais si vous utilisez des variables de classe, mais ce n'est pas couramment utilisé par la plupart des développeurs. En fait, les variables locales et d'instance sont susceptibles de représenter plus de 98% des variables dans votre application, donc c'est une bonne idée de les connaître.

comme son nom l'indique, les variables d'instance sont disponibles pour une instance spécifique. Il y a une syntaxe spécifique pour définir les variables d'instance, vous devez utiliser le signe @ pour définir une variable. Voici un exemple réel de mon propre travail:

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

dans ce code, vous pouvez voir qu'il y a une variable d'instance appelée @portfolio_items . Cette variable est créée dans la méthode index et n'est pas disponible à d'autres méthodes dans le fichier. Pourquoi n'ai-je pas simplement fait de cette variable une variable locale puisqu'elle n'est pas disponible pour les autres méthodes de la classe?

la raison en est que les Rails sont structurés de telle manière que les fichiers view et controller sont câblés pour communiquer entre eux, donc cette variable d'instance @portfolio_items peut être consulté dans l'associées vue fichier comme ceci:

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

maintenant, @portfolio_items sont disponibles au singulier pour la page de vue uniquement parce que j'en ai fait une variable d'instance dans le fichier de contrôle.

0
répondu Daniel 2018-06-11 13:18:12