类变量和类实例变量之间的区别?

时间:2010-09-27 09:32:14

标签: ruby class-variables class-instance-variables

有人能告诉我类变量和类实例变量之间的区别吗?

3 个答案:

答案 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