dyn prefix(@Rust)

https://doc.rust-jp.rs/rust-by-example-ja/trait/dyn.html

におそらくdyn(dynamicの略)の典型的使い方(トレイトの戻り値型で必須のprefixキーワード)だろうと思われるコードが出てきます。

dynの説明、

https://doc.rust-lang.org/std/keyword.dyn.html

によると、dyn Traitは二つの参照ポインタを持つようで、

データへの参照(この場合にはstruct)ポインタ情報

② 通称vtableと呼ばれる関数ポインタマップへのポインタ情報

struct Sheep {}
struct Cow {}

trait Animal {
    // Instance method signature
    fn noise(&self) -> &'static str;
}

// Implement the `Animal` trait for `Sheep`.
impl Animal for Sheep {
    fn noise(&self) -> &'static str {
        "baaaaah!"
    }
}

// Implement the `Animal` trait for `Cow`.
impl Animal for Cow {
    fn noise(&self) -> &'static str {
        "moooooo!"
    }
}

// Returns some struct that implements Animal, but we don't know which one at compile time.
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());
}

戻り値には選択的に二種類の構造体のヒープエリアBox::new(struct{})を指定していますが、コンパイル時には”animal”はそれぞれの構造体にリンクされるので、戻り情報のBox::new(struct{})には”animal”関数も含まれている(上記の①と②)から”animal.noise()“がアクセス可能となります。

もし戻り値の型が確定的であれば、例えばBox<Sheep>で問題ないのは蛇足で、確定できないからトレイトを戻り型にしている訳で、そのためのdynです。

動的なポインター割り当てなので、性能的には当然オーバーヘッドが出てきますが、コードの分かり易さの点からはこの記法で問題ないケースが大半だろうと思います。

 

admin

カテゴリーRust