【问题标题】:Ruby - Structs and named parameters inheritanceRuby - 结构和命名参数继承
【发布时间】:2011-07-31 17:59:13
【问题描述】:

这个问题完全是关于 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 会变得暴躁,当然。那么鉴于这个说明性代码,如何使用这种类型的类继承来继承命名参数呢?

【问题讨论】:

    标签: ruby inheritance struct


    【解决方案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 添加到结构中:

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

    【讨论】:

    • 凡是定义derived_struct的地方,都可以将Person替换成self,这样子类中才能正常使用该方法。如果您定义Struct#derived_struct,这一点尤其重要。
    【解决方案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 的子类。

    【讨论】:

      【解决方案3】:

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

      但我真的不明白为什么需要这样的东西。

      【讨论】:

        猜你喜欢
        • 2020-05-16
        • 1970-01-01
        • 2011-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-12
        • 2018-03-28
        • 1970-01-01
        相关资源
        最近更新 更多