Ruby - наследование структур и именованных параметров - PullRequest
14 голосов
/ 31 июля 2011

Этот вопрос касается исключительно поведения Структуры, поэтому, пожалуйста, не спрашивайте: «Почему в широком мире спорта вы делаете это именно так?»

Этот код НЕПРАВИЛЬНЫЙ, но он должен проиллюстрировать то, что я пытаюсь понять о 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 или PolitPerson, конечно. Итак, учитывая этот иллюстративный код, как можно наследовать именованные параметры, используя этот тип наследования классов, используя Structs?

Ответы [ 3 ]

16 голосов
/ 31 июля 2011

Вы можете определить новые Структуры, основанные на Персоне:

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 голосов
/ 10 января 2014

Ruby начинает капризничать, когда вы пытаетесь инициализировать ReligiousPerson или PolitPerson, конечно,

Я думаю, что более вероятно, что он выдает ошибку, когда вы пытаетесь определить 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.

0 голосов
/ 31 июля 2011

Нет, это не структуры, которые не должны использоваться в цепочке наследования (на самом деле не имеет смысла иметь struct наследовать от другой, на самом деле).Что вы могли бы сделать, это создать свой собственный класс Struct и реализовать то же поведение, но хранить имена атрибутов в унаследованной переменной класса (с class_inheritable_accessor ).

Но я не могу понять, почему что-то подобное может понадобиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...