Ruby类实例变量和继承
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ruby类实例变量和继承相关的知识,希望对你有一定的参考价值。
我有一个名为LibraryItem
的Ruby类。我想与该类的每个实例关联一个属性数组。这个数组很长,看起来像
['title', 'authors', 'location', ...]
请注意,这些属性并不是真正应该作为方法,而只是LibraryItem
具有的属性列表。
接下来,我要创建一个名为LibraryItem
的子类,该子类具有一个属性数组,该属性数组包含LibraryBook
的所有属性,但还将包含更多属性。
[最终,我将需要LibraryItem
的多个子类,每个子类具有它们自己的数组LibraryItem
,但是每个子类都添加到@attributes
的LibraryItem
上(例如@attributes
,LibraryBook
,LibraryDVD
等)。
所以,这是我的尝试:
LibraryMap
这不起作用。我得到错误
class LibraryItem < Object
class << self; attr_accessor :attributes; end
@attributes = ['title', 'authors', 'location',]
end
class LibraryBook < LibraryItem
@attributes.push('ISBN', 'pages')
end
如果可以,我想要这样的东西
undefined method `push' for nil:NilClass
输出
puts LibraryItem.attributes
puts LibraryBook.attributes
((2010年5月2日添加)一种解决方案是使['title', 'authors', 'location']
['title', 'authors', 'location', 'ISBN', 'pages']
成为简单的实例变量,然后在@attributes
方法中添加LibraryBoot
的新属性(这是demas在答案之一中提出的)。
虽然这肯定会起作用(事实上,这是我一直在做的事情),但我对此并不满意,因为它不是最优的:为什么每次创建对象时都要构造这些不变的数组?
我真正想要的是具有可以从父类继承的类变量,但是在子类中进行更改时,在父类中不进行更改。
由于您提到的属性是“固定的”和“不变的”,所以我假设您的意思是一旦创建对象就永远不会更改其值。在这种情况下,应执行以下操作:
initialize
您正在手动实现一个伪装数组内部名称的读取器方法(而不是让class Foo
ATTRS = ['title', 'authors', 'location']
def attributes
ATTRS
end
end
class Bar < Foo
ATTRS = ['ISBN', 'pages']
def attributes
super + ATTRS
end
end
为您创建)。在子类中,您只需调用祖先类的reader函数,添加与子类关联的其他字段,然后将其返回给调用者即可。对于用户,这看起来像一个名为attr_accessor
的只读成员变量,该变量在子类中具有其他值。
另一种解决方案是使用inherited钩子:
attributes
只是一个版本:
class LibraryItem < Object
class << self
attr_accessor :attributes
def inherit_attributes(attrs)
@attributes ||= []
@attributes.concat attrs
end
def inherited(sublass)
sublass.inherit_attributes(@attributes)
end
end
@attributes = ['title', 'authors', 'location',]
end
class LibraryBook < LibraryItem
@attributes.push('ISBN', 'pages')
end
出于好奇,这样的事情会起作用吗?
class LibraryItem < Object
def initialize
@attributes = ['one', 'two'];
end
end
class LibraryBook < LibraryItem
def initialize
super
@attributes.push('three')
end
end
b = LibraryBook.new
这似乎会产生预期的结果-创建类对象时ATTRIBUTES数组被扩展,并且ATTRIBUTES的值按预期变化:
class Foo
ATTRIBUTES = ['title','authors','location']
end
class Bar < Foo
ATTRIBUTES |= ['ISBN', 'pages']
end
ActiveSupport在rails edge中具有class_attribute方法。
要扩展@Nick Vanderbilt的答案,请使用active_support执行此操作,这正是我想要此功能的简写。这是一个完整的示例:
> Foo::ATTRIBUTES
=> ['title','authors','location']
> Bar::ATTRIBUTES
=> ['title','authors','location', 'ISBN', 'pages']
可耻的是,Ruby不需要库就很难做到这一点。这是我唯一想念python的东西。就我而言,我不介意对active_support gem的依赖。
在LibraryBook中,变量@attributes是一个新的自变量,是对象LibraryBook的实例变量,因此未初始化,并且会出现错误“未定义的方法...为nil”在使用
之前,您应该通过LibraryItem属性列表进行初始化。require 'active_support/core_ext'
class Foo
class_attribute :attributes
self.attributes = ['title','authors','location']
end
class Bar < Foo
self.attributes = Foo.attributes + ['ISBN', 'pages']
end
puts Foo.attributes.inspect #=> ["title", "authors", "location"]
puts Bar.attributes.inspect #=> ["title", "authors", "location", "ISBN", "pages"]
这是用于字符串(实际上是任何东西),而不是数组,但是...
class LibraryBook < LibraryItem
@attributes = LibraryItem::attributes + ['ISBN', 'pages']
end
您也可以使用常量来完成。虽然没有检查。
class A
def self.a
@a || superclass.a rescue nil
end
def self.a=(value)
@a = value
end
self.a = %w( apple banana chimp )
end
class B < A
end
class C < B
self.a += %w( dromedary elephant )
end
class D < A
self.a = %w( pi e golden_ratio )
end
irb(main):001:0> require 'test2'
=> true
irb(main):002:0> A.a
=> ["apple", "banana", "chimp"]
irb(main):003:0> B.a
=> ["apple", "banana", "chimp"]
irb(main):004:0> C.a
=> ["apple", "banana", "chimp", "dromedary", "elephant"]
irb(main):005:0> D.a
=> ["pi", "e", "golden_ratio"]
irb(main):006:0> A.a = %w( 7 )
=> ["7"]
irb(main):007:0> A.a
=> ["7"]
irb(main):008:0> B.a
=> ["7"]
irb(main):009:0> C.a = nil
=> nil
irb(main):010:0> C.a
=> ["7"]
以上是关于Ruby类实例变量和继承的主要内容,如果未能解决你的问题,请参考以下文章