2015-09-13 8 views
6

rust 1.2.01つの構造体が既存の構造体を拡張し、すべてのフィールドを保持することは可能ですか?使用

問題私は錆を(Javascriptの背景から来る)学習の過程ではまだだと既存を拡張するために、1つのstruct StructBことは可能であるかどうかを把握しようとしています

struct StructAのように、StructBにはすべてStructAに定義されたフィールドがあります。私はこのような何かを、本質的に可能性がJavaScriptで

(ES6構文)...

class Person { 
    constructor (gender, age) { 
     this.gender = gender; 
     this.age = age; 
    } 
} 
class Child extends Person { 
    constructor (name, gender, age) { 
     super(gender, age); 
     this.name = name; 
    } 
} 

制約

  • StructAは、私は何のコントロールの上に持っていない外部cargoパッケージからです。

現在の進行状況

は私が必要とする正確に何のように聞こえるこのblog post on single-inheritanceを見つけました。

しかし、実装しようとすると、このエラーメッセージerror: virtual structs have been removed from the languageが発生しました。後で検索する人もいれば、すぐにimplemented and then removed per RFC-341になっていたことがわかりました。

また、thread about using traitsが見つかりましたが、StructAは外部の貨物パッケージからのものですので、私はそれを特性に変えることはできません。

これでRustでこれを達成する正しい方法は何でしょうか?

答えて

13

正確には一致するものはありません。心に浮かぶ2つの概念があります。

  1. 構造組成

    struct Person { 
        age: u8, 
    } 
    
    struct Child { 
        person: Person, 
        has_toy: bool, 
    } 
    
    impl Person { 
        fn new(age: u8) -> Self { 
         Person { age: age } 
        } 
    
        fn age(&self) -> u8 { 
         self.age 
        } 
    } 
    
    impl Child { 
        fn new(age: u8, has_toy: bool) -> Self { 
         Child { person: Person::new(age), has_toy: has_toy } 
        } 
    
        fn age(&self) -> u8 { 
         self.person.age() 
        } 
    } 
    
    fn main() { 
        let p = Person::new(42); 
        let c = Child::new(7, true); 
    
        println!("I am {}", p.age()); 
        println!("My child is {}", c.age()); 
    } 
    

    あなたは、単に他に1つの構造体を埋め込むことができます。メモリレイアウトはすばらしくコンパクトですが、PersonからChildにすべてのメソッドを手動で委譲するか、&Personを貸し出す必要があります。

  2. トレイト

    trait SayHi { 
        fn say_hi(&self); 
    } 
    
    struct Person { 
        age: u8, 
    } 
    
    struct Child { 
        age: u8, 
        has_toy: bool, 
    } 
    
    impl SayHi for Person { 
        fn say_hi(&self) { 
         println!("Greetings. I am {}", self.age) 
        } 
    } 
    
    impl SayHi for Child { 
        fn say_hi(&self) { 
         if self.has_toy { 
          println!("I'm only {}, but I have a toy!", self.age) 
         } else { 
          println!("I'm only {}, and I don't even have a toy!", self.age) 
         } 
        } 
    } 
    
    fn greet<T>(thing: T) 
        where T: SayHi 
    { 
        thing.say_hi() 
    } 
    
    fn main() { 
        let p = Person { age: 42 }; 
        let c = Child { age: 7, has_toy: true }; 
    
        greet(p); 
        greet(c); 
    } 
    

もちろん、これら二つの概念を組み合わせることができます。


DK. mentionsとして、あなたはDerefDerefMutを実装することを選択することができます。しかし、私はこれらの形質をこのように使用すべきではないことに同意します。私の議論は、古典的なオブジェクト指向の継承を単にコードの再利用に使うのは間違っているという議論に似ています。 「継承を超えた構成を優先」=>「Derefを超える構成」。しかし、私は、簡潔な代表団を可能にする言語機能の希望を抱いて、構成の面倒を減らしています。

+0

これは私が疑ったものです。迅速な回答を確認してくれてありがとう!ありがとう!そこのnoobsの残りの部分については...これらのスニペットはあなたのためにコンパイルしますか? 'new'の戻り値の型がなければコンパイルエラーが出ます。 – drebabels

+0

@drebabelsいいえ、それは私の間違いです。私はそれが今コンパイルされていることを確かめました:-) – Shepmaster

+2

@Shepmaster: 'Deref 'と 'Child'の' DerefMut'を実装することは、構図アプローチがうまく動作するように長い道を行くでしょう。なぜなら、ほとんどの場合、 'Child'は' Person'のように扱うことができるからです。 –

9

錆にはどのような種類の構造体継承もありません。 StructBStructAと同じフィールドを含めるには、構図を使用する必要があります。また

struct StructB { 
    a: StructA, 
    // other fields... 
} 

、明確にする、特徴は、方法および関連タイプを定義するのみことが可能です。彼らはできませんフィールドを定義します。

あなたはStructAとしてStructBを使用できるようにしたい場合は、コンパイラが暗黙的にポインタにStructB SへのポインタをキャストすることができますDerefDerefMut特性を、実装することにより、そこに道の一部を得ることができます〜StructAs:

struct StructA; 

impl StructA { 
    fn name(&self) -> &'static str { 
     "Anna" 
    } 
} 

struct StructB { 
    a: StructA, 
    // other fields... 
} 

impl std::ops::Deref for StructB { 
    type Target = StructA; 
    fn deref(&self) -> &Self::Target { 
     &self.a 
    } 
} 

fn main() { 
    let b = StructB { a: StructA }; 
    println!("{}", b.name()); 
} 
関連する問題