可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I read \"When do Ruby instance variables get set?\" but I\'m of two minds when to use class instance variables.
Class variables are shared by all objects of a class, Instance variables belong to one object. There\'s not much room left to use class instance variables if we have class variables.
Could someone explain the difference between these two and when to use them?
Here\'s a code example:
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
I understand now, Class Instance Variables are not passed along the inheritance chain!
回答1:
Instance variable on a 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]
Class variable:
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]
With an instance variable on a class (not on an instance of that class) you can store something common to that class without having sub-classes automatically also get them (and vice-versa). With class variables, you have the convenience of not having to write self.class
from an instance object, and (when desirable) you also get automatic sharing throughout the class hierarchy.
Merging these together into a single example that also covers instance variables on 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
And then in 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]
回答2:
I believe the main (only?) different is inheritance:
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
Class variables are shared by all \"class instances\" (i.e. subclasses), whereas class instance variables are specific to only that class. But if you never intend to extend your class, the difference is purely academic.
回答3:
#class instance variable are available only to class method and not to instance methods whereas class variable are avilable to both instance methods and class methods. Also the class instance variables are lost in inheritance chain whereas class variables are not.
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
回答4:
As others said, class variables are shared between a given class and its subclasses. Class instance variables belong to exactly one class; its subclasses are separate.
Why does this behavior exist? Well, everything in Ruby is an object—even classes. That means that each class has an object of the class Class
(or rather, a subclass of Class
) corresponding to it. (When you say class Foo
, you\'re really declaring a constant Foo
and assigning a class object to it.) And every Ruby object can have instance variables, so class objects can have instance variables, too.
The trouble is, instance variables on class objects don\'t really behave the way you usually want class variables to behave. You usually want a class variable defined in a superclass to be shared with its subclasses, but that\'s not how instance variables work—the subclass has its own class object, and that class object has its own instance variables. So they introduced separate class variables with the behavior you\'re more likely to want.
In other words, class instance variables are sort of an accident of Ruby\'s design. You probably shouldn\'t use them unless you specifically know they\'re what you\'re looking for.
回答5:
So as you know a class variable are variables that are available to a specific class and the syntax looks like so:
class myClass
@@teams = [\"A\'s\",\"Tigers\"]
end
However, you\'ll rarely use class variables in real-world applications because you can accomplish the same through local or instance variables. Nothing is wrong if you use class variables, but its not commonly utilized by most developers. In fact, the local and instance variables are likely to make up more than 98 percent of variables in your application, so it\'s a good idea to be familiar with them.
As the name suggests, instance variables are available to a specific instance. There is a specific syntax to set instance variables, you need to use the @ sign to define a variable. Here is a real-world example from my own work:
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
In this code, you can see that there is an instance variable called @portfolio_items. This variable is created in the method index and is not available to other methods in the file. Now, why did I not just make this a local variable since it\'s not available to other methods in the class?
The reason for this is because Rails is structured in such a way that the view and controller files are wired to communicate with each other, so this instance variable @portfolio_items can be accessed in the associated view file like so:
<%= form_for(@portfolio_item) do |f| %>
<% if @portfolio_item.errors.any? %>
<% @portfolio_item.errors.full_messages.each do |error| %>
<% alert_generator error %>
<% end %>
<% end %>
Now, @portfolio_items are available in the singular for the view page only because I made it an instance variable in the controller file.