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.
精彩评论