关于ruby类变量的混淆

关于ruby类变量的混淆,ruby,class-variables,Ruby,Class Variables,假设一个使用类变量的简单ruby程序 class Holder @@var = 99 def Holder.var=(val) @@var = val end def var @@var end end @@var = "top level variable" a = Holder.new puts a.var 我猜结果应该是99,但输出不是99。我想知道为什

假设一个使用类变量的简单ruby程序

    class Holder
      @@var = 99
      def Holder.var=(val)
        @@var = val
      end
      def var
        @@var
      end
    end

    @@var = "top level variable"

    a = Holder.new
    puts a.var

我猜结果应该是
99
,但输出不是
99
。我想知道为什么。由于类变量的作用域是类,我假定行
@@var=“top level variable”
不会影响类中的变量。

@@var
Holder
的类变量。顶层的
@@var
不是
Holder
的同名类变量
@@var
,而是您正在为类
对象创建一个全新的类变量。现在
@@var
与父类的子类共享
Object
是类
Holder
的父类。在Ruby中,如果没有显式定义任何自定义类的超类,则使用
class
关键字进行定义,然后
Object
类成为该类的默认超类,您只需创建

在顶层,您正在类
对象中定义一个新的类变量,就像您在发布的示例中所做的那样。通过继承,类
持有者现在可以使用它

我是说,当你写下以下内容时:

class Holder
  @@var = 99
  def Holder.var=(val)
    @@var = val
  end
  def var
    @@var
  end
end
@@var
尚未添加到
对象
类中。现在在顶层,当您写下以下行时:

@@var = "top level variable"
这意味着,您正在将它添加到
对象
类中,并更新旧变量(
@@var
)与
持有者
类一中相同的名称,使用这个新变量,您刚刚在
对象
类的范围中定义

请记住,类变量是共享变量,仅对类(
B
)可见,您在其中定义了它及其子类(
C
),子类(
C
)的子类(
D
)等等。但在父类(
A
)中定义了与子类(
B
)中相同的名称变量之前,类(
B
)的超类(
A
)不可见

A类
结束
B类
我想详述其他人所说的,特别是比较类变量和类实例变量的使用。让我们从这个开始:

class Holder1
end

class Holder2 < Holder1
  @@var = 99

  # Create a class setter and a getter for the class variable
  def Holder2.var=(val)
    @@var = val
  end

  def Holder2.var
    @@var
  end

  # Create a instance getter for the class variable
  def var
    @@var
  end
end

class Holder3 < Holder2
end

Holder2.var     #=> 99
Holder2.var = 1
Holder3.var     #=> 1
Holder1.var     #=> NoMethodError: undefined method `var' for Holder1:Class
Holder2.new.var #=> 1
Holder3.new.var #=> 1

Holder3.var = 2
Holder3.var     #=> 2
Holder2.var     #=> 2
Holder3.new.var #=> 2
Holder2.new.var #=> 2
这是因为在创建方法时,
self
=>
Holder2
。通过不硬连接类名,如果决定重命名该类,则无需进行任何更改

现在,这(类变量的使用)可能正是您想要的行为。也就是说,如果您希望子类看到变量并能够对其进行更改,则需要一个类变量

但是,如果希望每个子类都有自己的变量,子类既不能看到也不能更改这些变量,则需要使用类实例变量
@var
,而不是类变量
@@var
。(从技术上讲,这并不完全正确,因为可以在程序中的任何位置使用
Holder2.instance\u variable\u get(:@var)
Holder2.instance\u variable\u set(:@var)

将下面代码的结果与上面代码的结果进行比较。我包含了一个与类实例变量同名的实例变量,
@var
,以说明它们与
@night
@day
一样不同

class Holder1
end

class Holder2 < Holder1
  # Create an accessor for the instance variable
  attr_accessor :var

  # Initialize class instance variable
  @var = 99

  # Create an accessor for the class instance variable
  class << self
    puts "self in 'class << self': #{self}"
    attr_accessor :var
    def our_dog
      "Diva"
    end
  end

  # Create a class method
  def self.our_cat
    puts "self in 'self.our_cat())' def: #{self}"
    "Teagan"
  end   

  # Create an instance setter and a getter for the class instance variable
  def c_ivar=(val)
    self.class.var = val
  end

  def c_ivar
    self.class.var
  end
end

class Holder3 < Holder2
end

                 #=> self in 'class << self': #<Class:Holder2>

Holder2.var      #=> 99
h2 = Holder2.new
h2.var           #=> nil

Holder2.var = 1
Holder2.var      #=> 1
h2.c_ivar        #=> 1
h2.c_ivar = 2
Holder2.var      #=> 2

h2.var           #=> nil
h2.var = 3
h2.var           #=> 3
Holder2.var      #=> 2

Holder3.var      #=> nil
Holder1.var      #=> NoMethodError: undefined method `var' for Holder1:Class

Holder3.var = 4
Holder3.var      #=> 4
Holder2.var      #=> 2
h3 = Holder3.new
h3.c_ivar        #=> 4 
h2.c_ivar        #=> 2

Holder3.our_dog  #=> "Diva"
Holder3.our_cat  #=> "self in 'self.our_cat())' def: Holder3"
                 #=> "Teagan"
这表明
our_cat()。因此,有人说,从技术上讲。这也告诉我们,我们可以将
my_cat
的定义移到
类中
  def self.var=(val)
    @@var = val
  end

  def self.var
    @@var
  end
class Holder1
end

class Holder2 < Holder1
  # Create an accessor for the instance variable
  attr_accessor :var

  # Initialize class instance variable
  @var = 99

  # Create an accessor for the class instance variable
  class << self
    puts "self in 'class << self': #{self}"
    attr_accessor :var
    def our_dog
      "Diva"
    end
  end

  # Create a class method
  def self.our_cat
    puts "self in 'self.our_cat())' def: #{self}"
    "Teagan"
  end   

  # Create an instance setter and a getter for the class instance variable
  def c_ivar=(val)
    self.class.var = val
  end

  def c_ivar
    self.class.var
  end
end

class Holder3 < Holder2
end

                 #=> self in 'class << self': #<Class:Holder2>

Holder2.var      #=> 99
h2 = Holder2.new
h2.var           #=> nil

Holder2.var = 1
Holder2.var      #=> 1
h2.c_ivar        #=> 1
h2.c_ivar = 2
Holder2.var      #=> 2

h2.var           #=> nil
h2.var = 3
h2.var           #=> 3
Holder2.var      #=> 2

Holder3.var      #=> nil
Holder1.var      #=> NoMethodError: undefined method `var' for Holder1:Class

Holder3.var = 4
Holder3.var      #=> 4
Holder2.var      #=> 2
h3 = Holder3.new
h3.c_ivar        #=> 4 
h2.c_ivar        #=> 2

Holder3.our_dog  #=> "Diva"
Holder3.our_cat  #=> "self in 'self.our_cat())' def: Holder3"
                 #=> "Teagan"
Holder2.singleton_methods #=> [:var, :var=, :our_dog, :our_cat]
module M
  attr_accessor :var
  def our_dog
    "Diva"
  end
end