Ruby 类实例变量和继承
我有一个名为 LibraryItem
的 Ruby 类。我想将这个类的每个实例与属性数组相关联。这个数组很长,看起来像这样:
['title', 'authors', 'location', ...]
注意,这些属性实际上并不是方法,只是 LibraryItem
具有的属性列表。
接下来,我想创建一个名为 LibraryBook
的 LibraryItem
子类,它具有一个属性数组,其中包含 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
输出
['title', 'authors', 'location']
['title', 'authors', 'location', 'ISBN', 'pages']
类似的内容(添加于 2010 年 5 月 2 日) 解决此问题的一种方法是使 @attributes
成为一个简单的实例变量,然后在 initialize
方法中添加 LibraryBoot
的新属性(这是建议的)由德马斯在其中一个答案中提出)。
虽然这肯定会起作用(事实上,这也是我一直在做的事情),但我对此并不满意,因为它不是最佳的:为什么每次创建对象时都要构造这些不变的数组?
我真正想要的是拥有可以从父类继承的类变量,但在子类中更改时不会在父类中更改。
I have a Ruby class called LibraryItem
. I want to associate with every instance of this class an array of attributes. This array is long and looks something like
['title', 'authors', 'location', ...]
Note that these attributes are not really supposed to be methods, just a list of attributes that a LibraryItem
has.
Next, I want to make a subclass of LibraryItem
called LibraryBook
that has an array of attributes that includes all the attributes of LibraryItem
but will also include many more.
Eventually I will want several subclasses of LibraryItem
each with their own version of the array @attributes
but each adding on to LibraryItem
's @attributes
(e.g., LibraryBook
, LibraryDVD
, LibraryMap
, etc.).
So, here is my attempt:
class LibraryItem < Object
class << self; attr_accessor :attributes; end
@attributes = ['title', 'authors', 'location',]
end
class LibraryBook < LibraryItem
@attributes.push('ISBN', 'pages')
end
This does not work. I get the error
undefined method `push' for nil:NilClass
If it were to work, I would want something like this
puts LibraryItem.attributes
puts LibraryBook.attributes
to output
['title', 'authors', 'location']
['title', 'authors', 'location', 'ISBN', 'pages']
(Added 02-May-2010)
One solution to this is to make @attributes
a simple instance variable and then add the new attributes for LibraryBoot
in the initialize
method (this was suggested by demas in one of the answers).
While this would certainly work (and is, in fact, what I have been doing all along), I am not happy with this as it is sub-optimal: why should these unchanging arrays be constructed every time an object is created?
What I really want is to have class variables that can inherit from a parent class but when changed in the child class do not change in the the parent class.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
另一种解决方案是使用 inherited 钩子:
Another solution would be to use the inherited hook:
既然您提到属性是“固定的”和“不变的”,我假设您的意思是一旦创建对象就永远不会更改它们的值。在这种情况下,类似下面的内容应该可以工作:
您手动实现一个读取器方法(而不是让
attr_accessor
为您创建它)来伪装数组的内部名称。在您的子类中,您只需调用祖先类的 reader 函数,添加与子类关联的其他字段,然后将其返回给调用者。对于用户来说,这看起来就像一个名为attributes
的只读成员变量,它在子类中具有其他值。Since you mention that the attributes are "fixed" and "unchanging", I am assuming that you mean that you will never change their value once the object is created. In that case, something like the following should work:
You are manually implementing a reader method (instead of letting
attr_accessor
create it for you) that disguises the internal name of the array. In your subclass, you simply call the ancestor class' reader function, tack on the additional fields associated with the child class, and return that to the caller. To the user, this appears like a read-only member variable namedattributes
that has additional values in the sub-class.就像一个版本:
Just as a version:
出于好奇,这样的事情会起作用吗?
这似乎会产生所需的结果 - 创建类对象时 ATTRIBUTES 数组会扩展,并且 ATTRIBUTES 的值会按预期变化:
Out of curiosity, will something like this work?
This would seem to produce the desired result - the ATTRIBUTES array is expanded when the class object is created, and the values of ATTRIBUTES varies as expected:
为了扩展@Nick Vanderbilt 的答案,使用 active_support 来执行此操作,这正是我想要的此功能的简写。这是一个完整的例子:
遗憾的是,红宝石在不需要库的情况下很难实现这一目标。这是我唯一怀念 python 的东西。就我而言,我不介意对 active_support gem 的依赖。
To expand on @Nick Vanderbilt's answer, using active_support you do this, which is exactly the short hand I want for this functionality. Here's a complete example:
Shame it's so difficult for ruby to achieve this without needing a library for it. It's the only thing I miss from python. And in my case, I don't mind the dependency on the active_support gem.
ActiveSupport 在 Rails Edge 中有 class_attribute 方法。
ActiveSupport has class_attribute method in rails edge.
在 LibraryBook 中,变量 @attributes 是一个新的自变量,是对象 LibraryBook 的实例变量,因此它未初始化,并且您会收到错误“未定义的方法... for nil”
在使用之前,您应该通过 LibraryItem 属性列表对其进行初始化
In LibraryBook variable @attributes is a new independent variable, instance variable of object LibraryBook, so its not initialized and you get error "undefined method ... for nil"
You should to initialize it by LibraryItem attribut's list before using
这是针对字符串(实际上是任何东西),而不是数组,但是......
This is for strings (anything really), rather than arrays, but...
您也可以使用常量来做到这一点。虽然没有检查。
You can do it using CONSTANTS also. No check though.