94

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

4

3 回答 3

157

类变量 ( @@) 在类及其所有后代之间共享。类实例变量 ( @) 不被类的后代共享。


类变量 ( @@)

让我们有一个类 Foo 和一个类变量@@i,以及用于读写的访问器@@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

我们可以在@i不影响 Foo 的情况下设置 Bar @i

Bar.i = 2
p Foo.i    # => 1
p Bar.i    # => 2
于 2010-09-27T10:48:12.897 回答
73

首先你必须明白类也是实例——类的实例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!"

请注意,实例变量 on 与实例上的实例变量完全无关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实例以及子类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,因为上面的奇怪行为,并推荐使用class instance variables代替。

于 2010-09-27T10:54:29.570 回答
0

另外我想补充一点,您可以从类@@的任何实例访问类变量 ()

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
于 2019-01-15T08:52:23.383 回答