开发者

Ruby - Structs and named parameters inheritance

开发者 https://www.devze.com 2023-03-24 07:36 出处:网络
This question is strictly about Struct behavior, so please no \"why in the wide world of sports are you doing it that way?\"

This question is strictly about Struct behavior, so please no "why in the wide world of sports are you doing it that way?"

This code is INCORRECT, but it should illustrate what I am trying to understand about 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')

As you开发者_如何学Go can see, there's an attempt to define a class inheritance using Structs. However, Ruby gets cranky when you try to initialize ReligiousPerson or PoliticalPerson, of course. So given this illustrative code, how is it possible to inherit named params using this type of class inheritance using Structs?


You could define new Structs, based in 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')

Result:

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

Immediate after posting my answer I had an idea:

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')

Works fine!

You may also add #derived_struct to Struct:

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


Ruby gets cranky when you try to initialize ReligiousPerson or PoliticalPerson, of course

I think it's more likely that it's erroring out when you try to define ReligiousPerson and PoliticalPerson. This is because Person(:religion) looks like an attempt to call Person as if it were a function. Obviously, that's not going to work because Person is a class.

It's perfectly valid though to subclass 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 isn't really doing anything special by the way, it's just dynamically creating a class based on the values you pass it. You are then creating a new class (Person) which subclasses the class created by Struct.new:

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

Person.superclass == new_struct #=> true

Also, you may want to take note of this property of some of the previous answers:

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

If you do it that way, ReligiousPerson is actually not a subclass of Person.


No, it isn't structs are not supposed to be used in an inheritance chain (it does not make much sense to have a struct inherit form another one, really). What you could possibly do is create your own Struct class and implement the same behaviour, but storing the attribute names in a inherited class variable (with class_inheritable_accessor).

But I can't really understand why something like this would ever be needed.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号