如何从Ruby中的子类访问超类变量

如何从Ruby中的子类访问超类变量,ruby,class,inheritance,Ruby,Class,Inheritance,我试图从一个子类访问一个类变量。我知道类变量不是继承的,这回答了为什么代码不能工作的问题,但是我不完全理解如何解决它 这是我的代码: Class A ... class << self def format(a, b) @format = a end def item(a, b) @item[a] = b end end end Class B < A format 4, 7 item 7,

我试图从一个子类访问一个类变量。我知道类变量不是继承的,这回答了为什么代码不能工作的问题,但是我不完全理解如何解决它

这是我的代码:

Class A
  ...
  class << self 
    def format(a, b)
      @format = a
    end

    def item(a, b)
      @item[a] = b
    end

  end
end

Class B < A
  format 4, 7

  item 7, 12
  ...
end

Class C < B
  item 7, 18
end 
因此,理解类变量不是继承的,是否可以使
C.format=>4
,或者我是否需要这样重构:

Class B < A
  format 4, 7
  item 7, 12
end

Class C < A
  format 4, 7
  item 7, 18
end
B类

我之所以要避免后者,是因为我有很多变量都是以同样的方式定义的(调用函数来设置类变量),我不想在类B和C之间复制所有代码,因为一个实例变量不同。

首先,要定义类,需要使用关键字
class
not
class

其次,没有理由向方法
A::format
传递它不使用的参数。因此,我把它改为只有一个论点

第三,在定义
A
之后,当第一次执行
A.item
时,将引发异常,因为尚未定义
@item
。具体来说,
@item
(与任何其他未定义的实例变量一样)在调用时将返回
nil
,并且
nil
没有方法
[]
。因此,我更改了方法
item
,将类实例变量(非类变量)
@item
初始化为空数组

class A
  class << self 
    def format(a)
      @format = a
    end    
    def item(a, b)
      @item = []
      @item[a] = b
    end
  end
end
如果试图执行
B.format
将引发异常,因为
B::format
需要两个参数。如果
B.format
要返回
B
的类实例变量
@format
的值,则需要编写:

B.instance_variable_get(:@format)
  #=> 4 
您可以为实例变量
@format
添加读写访问器,在这种情况下,您的代码会稍微简化:

class A
  class << self
    attr_accessor :format
    def item(a, b)
      @item = []
      @item[a] = b
    end
  end
end
我知道类变量不是继承的

这是完全错误的,您还没有真正理解类变量是什么

Ruby中的类变量是用
@
符号声明的。他们肯定是继承的:

class A
  @@x= "Hello World"

end

class B < A
  puts @@x # Outputs "Hello World"
end
A类
@@x=“你好,世界”
结束
B类
类变量实际上在类及其子类之间共享:

class Animal
  @@greating = "Hello"
  def greet
    "#{@@greating} I'm a #{self.class.name.downcase}"
  end
end

class Cat < Animal
  @@greating = "Meow"
end

class Dog < Animal
  @@greating = "Woof"
end

puts Dog.new.greet # Woof I'm a dog
puts Cat.new.greet # Woof I'm a cat
puts Animal.new.greet # Woof I'm a animal
类动物
@@greating=“你好”
def问候
“{@greating}我是一个{self.class.name.downcase}”
结束
结束
猫类<动物类
@@greating=“喵喵”
结束
类狗<动物
@@greating=“Woof”
结束
我是一只狗
我是一只猫
我是一只动物
从示例中可以看出,这通常会导致意外和不希望的效果。类变量不被认为是线程安全的

您实际设置的是a-这只是一个实例变量,只是它的作用域不是a的实例。相反,它的作用域是作为类实例的单例类a

与真正的类变量不同,真正的类变量有自己的sigil类,实例变量不像它们的作用域那样在类及其子类之间共享。每个子类都有自己的单例类

class Animal
  @greating = "Hello"

  def self.greeting
    @greating
  end

  def greet
    "#{self.class.greeting} I'm a #{self.class.name.downcase}"
  end
end

class Cat < Animal
  @greating = "Meow"
end

class Dog < Animal
  @greating = "Woof"
end

puts Dog.new.greet # Woof I'm a dog
puts Cat.new.greet # Meow I'm a cat
puts Animal.new.greet # Hello I'm a animal
类动物
@greating=“你好”
自我问候
@变灰
结束
def问候
“{self.class.greeting}我是{self.class.name.downcase}”
结束
结束
猫类<动物类
@greating=“喵喵”
结束
类狗<动物
@greating=“Woof”
结束
我是一只狗
我是一只猫
喂,我是一只动物
类实例变量实际上比真正的类变量有用得多。如果要用类实例变量模拟类变量的继承,可以使用Ruby提供的回调函数:

class A
  @x = [self.name]
  class << self
    attr_accessor :x
    def inherited(subclass)
      puts "#{subclass.name} is inheriting from #{self.name}"
      subclass.x = x
      subclass.x.push(subclass.name)
    end
  end
end

class B < A; end # outputs "B is inheriting from A"
class C < B; end # outputs "C is inheriting from B"
puts B.x.inspect # => ['A', 'B']
puts C.x.inspect # => ['A', 'B', 'C']
A类
@x=[self.name]
类别['A','B']
放置C.x.inspect#=>['A','B','C']

为什么不创建一个模块并将变量(可能作为attr_访问器)放在那里?代码中没有类变量。你是指实例变量吗?在示例
class B
format=4
这将只设置局部变量
format
。您需要显式指定recent
self.format=4
或直接设置实例变量
@format=4
。谢谢@max.初学者的错误。
class B < A
  @format = 4
  item 7, 12
end
class C < B
  item 7, 18
  def self.format
    superclass.format
  end
end
C.format
  #=> 4 
class A
  @@x= "Hello World"

end

class B < A
  puts @@x # Outputs "Hello World"
end
class Animal
  @@greating = "Hello"
  def greet
    "#{@@greating} I'm a #{self.class.name.downcase}"
  end
end

class Cat < Animal
  @@greating = "Meow"
end

class Dog < Animal
  @@greating = "Woof"
end

puts Dog.new.greet # Woof I'm a dog
puts Cat.new.greet # Woof I'm a cat
puts Animal.new.greet # Woof I'm a animal
class Animal
  @greating = "Hello"

  def self.greeting
    @greating
  end

  def greet
    "#{self.class.greeting} I'm a #{self.class.name.downcase}"
  end
end

class Cat < Animal
  @greating = "Meow"
end

class Dog < Animal
  @greating = "Woof"
end

puts Dog.new.greet # Woof I'm a dog
puts Cat.new.greet # Meow I'm a cat
puts Animal.new.greet # Hello I'm a animal
class A
  @x = [self.name]
  class << self
    attr_accessor :x
    def inherited(subclass)
      puts "#{subclass.name} is inheriting from #{self.name}"
      subclass.x = x
      subclass.x.push(subclass.name)
    end
  end
end

class B < A; end # outputs "B is inheriting from A"
class C < B; end # outputs "C is inheriting from B"
puts B.x.inspect # => ['A', 'B']
puts C.x.inspect # => ['A', 'B', 'C']