Ruby - Наследование структур и названных параметров
Этот вопрос строго о стиле поведения, поэтому, пожалуйста, "почему в широком мире спорта вы так делаете?"
Этот код INCORRECT, но он должен показать, что я пытаюсь понять о 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. Тем не менее, Ruby становится неуклюжим, когда вы пытаетесь инициализировать ReligiousPerson или PolicyPerson, конечно. Итак, учитывая этот иллюстративный код, как можно наследовать именованные параметры, используя этот тип наследования классов, используя Structs?
Ответы
Ответ 1
Вы можете определить новые структуры, основанные на 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
Ответ 2
Ruby становится расстроенным, когда вы пытаетесь инициализировать ReligiousPerson или PolicyPerson, конечно
Я думаю, что более вероятно, что это ошибка, когда вы пытаетесь определить ReligiousPerson
и PoliticalPerson
. Это связано с тем, что 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
.
Ответ 3
Нет, это не значит, что структуры не должны использоваться в цепочке наследования (не имеет смысла иметь наследование struct на самом деле наследует другую). То, что вы могли бы сделать, это создать свой собственный класс Struct и реализовать такое же поведение, но сохранить имена атрибутов в унаследованной переменной класса (с class_inheritable_accessor).
Но я не могу понять, почему что-то подобное понадобится.