如何从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
notclass
其次,没有理由向方法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
。您需要显式指定recentself.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']