Ruby类实例变量和继承

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ruby类实例变量和继承相关的知识,希望对你有一定的参考价值。

我有一个名为LibraryItem的Ruby类。我想与该类的每个实例关联一个属性数组。这个数组很长,看起来像

['title', 'authors', 'location', ...]

请注意,这些属性并不是真正应该作为方法,而只是LibraryItem具有的属性列表。

接下来,我要创建一个名为LibraryItem的子类,该子类具有一个属性数组,该属性数组包含LibraryBook的所有属性,但还将包含更多属性。

[最终,我将需要LibraryItem的多个子类,每个子类具有它们自己的数组LibraryItem,但是每个子类都添加到@attributesLibraryItem上(例如@attributesLibraryBookLibraryDVD等)。

所以,这是我的尝试:

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类实例变量和继承的主要内容,如果未能解决你的问题,请参考以下文章

Ruby元编程

Ruby类和实例变量跨继承生命周期演示

您是不是曾经在任何 Ruby 代码中使用过“类实例变量”?

Ruby变量

3.ruby语法基础,全部变量,实例变量,类变量,局部变量的使用和注意的要点

Ruby的attr_accessor如何产生类变量或类实例变量而不是实例变量?