Dyn を使ったトレイトの返却

RustRustBeginner
オンラインで実践に進む

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、Animal トレイトを直接返す制限を回避する方法を学びます。これは、Box<dyn Animal> 型を使用することで可能で、関数が Animal トレイトを実装するヒープ割り当てオブジェクトへの参照を返すことができるようになります。

注: 実験でファイル名が指定されていない場合は、好きなファイル名を使用できます。たとえば、main.rs を使用して、rustc main.rs &&./main でコンパイルして実行できます。

dyn を使ったトレイトの返却

Rust コンパイラは、各関数の戻り値の型がどれだけのメモリを必要とするかを知る必要があります。これは、すべての関数が具体的な型を返さなければならないことを意味します。他の言語とは異なり、Animal のようなトレイトを持っている場合、Animal を返す関数を書くことはできません。なぜなら、その異なる実装では異なる量のメモリが必要になるからです。

しかし、簡単な回避策があります。トレイト オブジェクトを直接返す代わりに、関数は Animal含む Box を返します。box は、ヒープ内の一部のメモリへの参照にすぎません。参照は静的に既知のサイズを持っており、コンパイラはそれがヒープ割り当ての Animal を指すことを保証できるため、関数からトレイトを返すことができます!

Rust は、ヒープ上にメモリを割り当てるときにできる限り明示的になろうとしています。そのため、関数がこのようにヒープ上のトレイトへのポインタを返す場合、戻り値の型を dyn キーワードを使って書く必要があります。たとえば、Box<dyn Animal> です。

struct Sheep {}
struct Cow {}

trait Animal {
    // インスタンス メソッドのシグネチャ
    fn noise(&self) -> &'static str;
}

// `Sheep` に対して `Animal` トレイトを実装する。
impl Animal for Sheep {
    fn noise(&self) -> &'static str {
        "baaaaah!"
    }
}

// `Cow` に対して `Animal` トレイトを実装する。
impl Animal for Cow {
    fn noise(&self) -> &'static str {
        "moooooo!"
    }
}

// `Animal` を実装する何らかの構造体を返すが、コンパイル時にどれが返されるかはわからない。
fn random_animal(random_number: f64) -> Box<dyn Animal> {
    if random_number < 0.5 {
        Box::new(Sheep {})
    } else {
        Box::new(Cow {})
    }
}

fn main() {
    let random_number = 0.234;
    let animal = random_animal(random_number);
    println!("You've randomly chosen an animal, and it says {}", animal.noise());
}

まとめ

おめでとうございます!Dyn を使ったトレイトの返却の実験を完了しました。技術力を向上させるために、LabEx でさらに実験を行って練習してください。