Zmienna instancji klasy Ruby vs. zmienna klasy

Czytam " Kiedy ustawiane są zmienne instancji Ruby? " ale mam dwa umysły, kiedy używać zmiennych instancji klasy.

Zmienne klasy są współdzielone przez wszystkie obiekty klasy, zmienne instancji należą do jednego obiektu. Nie ma zbyt wiele miejsca na użycie zmiennych instancji klasy, jeśli mamy zmienne klasy.

Czy ktoś mógłby wyjaśnić różnicę między tymi dwoma i kiedy ich używać?

Oto przykład kodu:

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

Rozumiem teraz, instancja klasy Zmienne nie są przekazywane wzdłuż łańcucha dziedziczenia!

Author: Community, 2013-04-03

5 answers

Zmienna instancji klasy:

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]

Zmienna Klasy:

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]

Ze zmienną instancji na klasie (nie na instancji tej klasy) można zapisać coś wspólnego dla tej klasy bez konieczności podklasy automatycznie również je dostać (i vice-versa). W przypadku zmiennych klasy masz wygodę, że nie musisz pisać self.class z obiektu instancji, a (jeśli jest to pożądane) otrzymujesz również automatyczne współdzielenie w całej hierarchii klas.


Łączenie tych razem w jednym przykładzie, który obejmuje również zmienne instancji na instancjach:

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

A potem w akcji:

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,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-27 18:45:10

I believe the main (only?) różne jest dziedziczenie:

class T < S
end

p T.k
=> 23

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

p T.s
=> nil

Zmienne klasy są współdzielone przez wszystkie "instancje klasy" (tj. podklasy), podczas gdy zmienne instancji klasy są specyficzne tylko dla tej klasy. Ale jeśli nigdy nie zamierzasz przedłużyć klasy, różnica jest czysto akademicka.

 30
Author: bioneuralnet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-02 20:23:29

# zmienne instancji klasy są dostępne tylko dla metody klasy, a nie dla metod instancji, podczas gdy zmienne klasy są dostępne zarówno dla metod instancji, jak i metod klasy. Również zmienne instancji klasy są tracone w łańcuchu dziedziczenia, podczas gdy zmienne klasy nie są.

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,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-25 18:03:38

Jak powiedzieli inni, zmienne klasy są współdzielone pomiędzy daną klasą i jej podklasami. Zmienne instancji klasy należą do dokładnie jednej klasy; jej podklasy są oddzielne.

Dlaczego takie zachowanie istnieje? Cóż, wszystko w Rubim jest obiektem-nawet klasami. Oznacza to, że każda klasa ma odpowiadający jej obiekt klasy Class (a raczej podklasę Class). (Kiedy mówisz class Foo, tak naprawdę deklarujesz stałą Foo i przypisujesz do niej obiekt klasy.) I każdy Rubin obiekt może mieć zmienne instancji, więc obiekty klas mogą mieć również zmienne instancji.

Problem polega na tym, że zmienne instancji w obiektach klasy nie zachowują się tak, jak zwykle chcesz, aby zmienne klasy zachowywały się. Zwykle chcesz, aby zmienna klasy zdefiniowana w superklasie była współdzielona z jej podklasami, ale nie tak działają zmienne instancji-podklasa ma swój własny obiekt klasy, A Ten obiekt klasy ma swoje własne zmienne instancji. Wprowadzili więc oddzielne zmienne klasowe z zachowanie, którego bardziej pragniesz.

Innymi słowy, zmienne instancji klasy są pewnego rodzaju wypadkiem projektu Rubiego. Prawdopodobnie nie powinieneś ich używać, chyba że wiesz, że są tym, czego szukasz.

 12
Author: Brent Royal-Gordon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-02 00:10:26

Więc jak wiesz zmienna klasy są zmiennymi, które są dostępne dla konkretnej klasy i składnia wygląda tak:

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

Jednak rzadko będziesz używać zmiennych klasy w rzeczywistych aplikacjach, ponieważ możesz to osiągnąć za pomocą zmiennych lokalnych lub instancji. Nic nie jest złe, jeśli używasz zmiennych klasy, ale nie jest powszechnie używany przez większość programistów. W rzeczywistości zmienne lokalne i instancyjne mogą stanowić ponad 98% zmiennych w aplikacji, więc dobrze jest się z nimi zapoznać.

Jak sama nazwa wskazuje, zmienne instancji są dostępne dla konkretnej instancji. Istnieje specyficzna składnia do ustawiania zmiennych instancji, musisz użyć @ podpisz, aby zdefiniować zmienną. Oto prawdziwy przykład z mojej własnej pracy:

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

W tym kodzie możesz zobaczyć, że istnieje zmienna instancji o nazwie @portfolio_items . Zmienna ta jest tworzona w metodzie index i nie jest dostępna dla innych metody w pliku. Dlaczego nie zrobiłem z tego zmiennej lokalnej, ponieważ nie jest ona dostępna dla innych metod w klasie?

Powodem tego jest to, że Rails jest skonstruowany w taki sposób, że pliki view i controller są podłączone do komunikacji między sobą, więc zmienna instancji @portfolio_items może być dostępna w powiązanym pliku view w następujący sposób:

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

Teraz, @portfolio_items są dostępne w liczbie pojedynczej dla strony widoku tylko dlatego, że zrobiłem z niej zmienną instancji w pliku kontrolera.

 0
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-11 13:18:12