有人能告诉我类变量和类实例变量之间的区别吗?
答案 0 :(得分:148)
类变量(@@
)在类及其所有后代之间共享。类的后代不共享类实例变量(@
)。
类变量(@@
)
让我们有一个带有类变量@@i
的类Foo,以及用于读写@@i
的访问器:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
派生类:
class Bar < Foo
end
我们看到Foo和Bar对@@i
具有相同的值:
p Foo.i # => 1
p Bar.i # => 1
在一个中更改@@i
会改变它们:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
类实例变量(@
)
让我们创建一个带有类实例变量@i
的简单类和用于读写@i
的访问器:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
派生类:
class Bar < Foo
end
我们看到虽然Bar继承了@i
的访问者,但它本身并不继承@i
:
p Foo.i # => 1
p Bar.i # => nil
我们可以设置Bar的@i
而不会影响Foo的@i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
答案 1 :(得分:68)
首先,您必须了解类也是实例 - Class
类的实例。
一旦理解了这一点,就可以理解一个类可以将实例变量与它相关联,就像常规(读取:非类)对象一样。
Hello = Class.new
# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")
# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"
请注意,Hello
上的实例变量与Hello
的实例上的实例变量完全无关且不同
hello = Hello.new
# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")
# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")
# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"
另一方面,类变量是上述两种的组合,因为它可以在Hello
本身及其实例上访问,也可以在{{1}的子类上访问和他们的实例:
Hello
由于上述奇怪行为,很多人都说要避免HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new
Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"
,并建议改为使用class variables
。
答案 2 :(得分:-1)
我还要补充一点,您可以从任何类实例访问类变量(@@
)
class Foo
def set_name
@@name = 'Nik'
end
def get_name
@@name
end
end
a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik
但是您不能对类实例变量(@
)进行相同操作
class Foo
def set_name
@name = 'Nik'
end
def get_name
@name
end
end
a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil