Ruby - Structs和命名参数继承

时间:2011-07-31 17:59:14

标签: ruby inheritance struct

这个问题严格关于结构行为,所以请不要“为什么在广泛的体育世界中你这样做呢?”

这段代码是不正确的,但它应该说明我想要了解的Ruby Structs:

class Person < Struct.new(:name, :last_name)
end

class ReligiousPerson < Person(:religion)
end

class PoliticalPerson < Person(:political_affiliation)
end

### Main ###

person = Person.new('jackie', 'jack')
pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
political_person = PoliticalPerson.new('frankie', 'frank', 'Connecticut for Lieberman')

如您所见,尝试使用Structs定义类继承。但是,当你尝试初始化ReligiousPerson或PoliticalPerson时,Ruby会变得暴躁。所以给定这个说明性代码,如何使用Structs使用这种类继承来继承命名参数?

3 个答案:

答案 0 :(得分:16)

您可以定义新的Structs,基于Person:

class Person < Struct.new(:name, :last_name)
end

class ReligiousPerson < Struct.new(*Person.members, :religion)  
end

class PoliticalPerson < Struct.new(*Person.members, :political_affiliation)
end

### Main ###

person = Person.new('jackie', 'jack')
p pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
p political_person = PoliticalPerson.new('frankie', 'frank', 'Connecticut for Lieberman')

结果:

#<struct ReligiousPerson name="billy", last_name="bill", religion="Zoroastrianism">
#<struct PoliticalPerson name="frankie", last_name="frank", political_affiliation="Connecticut for Lieberman">

在发布我的回答后,我立即知道了:

class Person < Struct.new(:name, :last_name)
  def self.derived_struct( *args )
    Struct.new(*self.members, *args)
  end
end

class ReligiousPerson < Person.derived_struct(:religion)  
end

class PoliticalPerson < Person.derived_struct(:political_affiliation)
end

### Main ###

person = Person.new('jackie', 'jack')
p pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
p political_person = PoliticalPerson.new('frankie', 'frank', 'Connecticut for Lieberman')

工作正常!

您也可以将#derived_struct添加到Struct:

class Struct
  def self.derived_struct( *args )
    Struct.new(*self.members, *args)
  end
end

答案 1 :(得分:2)

  当你尝试初始化ReligiousPerson或PoliticalPerson时,Ruby会变得暴躁,当然

我认为当你尝试定义 ReligiousPersonPoliticalPerson时,它更有可能出错。这是因为Person(:religion)看起来像是试图调用Person,就像它是一个函数一样。显然,这不会起作用,因为Person是一个类。

尽管继承Person:

,但它完全有效
class ReligiousPerson < Person
  attr_accessor :religion

  def initialize(name, last_name, religion)
    super(name, last_name)
    @religion = religion
  end
end

pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
pious_person.religion #=> "Zoroastrianism"

Struct.new并没有真正做任何特别的事情,它只是根据你传递的值动态创建一个类。然后,您正在创建一个新类(Person),该类是由Struct.new创建的类的子类:

new_struct = Struct.new(:name, :last_name)
class Person < new_struct
end  

Person.superclass == new_struct #=> true

另外,您可能需要注意以前的一些答案的这个属性:

class Person < Struct.new(:name, :last_name)
end

class ReligiousPerson < Struct.new(*Person.members, :religion)  
end

ReligiousPerson.ancestors.include?(Struct) #=> true
ReligiousPerson.ancestors.include?(Person) #=> false

如果您这样做,ReligiousPerson实际上不是 Person的子类。

答案 2 :(得分:0)

不,结构不应该在继承链中使用(将 struct 继承形成另一个结构没有多大意义,真的)。您可能要做的是创建自己的 Struct 类并实现相同的行为,但将属性名称存储在继承的类变量中(使用class_inheritable_accessor)。

但我真的不明白为什么会有这样的事情需要。