新しいキーワード
概要
動機
トレイトオブジェクトを表す dyn Trait
dyn Trait
機能は、トレイトオブジェクトを使うための新しい構文です。簡単に言うと:
Box<Trait>
はBox<dyn Trait>
になり、&Trait
と&mut Trait
は&dyn Trait
と&mut dyn Trait
になる
といった具合です。プログラム内では:
#![allow(unused)] fn main() { trait Trait {} impl Trait for i32 {} // old // いままで fn function1() -> Box<Trait> { unimplemented!() } // new // これから fn function2() -> Box<dyn Trait> { unimplemented!() } }
これだけです!
なぜ?
トレイトオブジェクトにトレイト名をそのまま使うのは悪手だったと、後になって分かりました。 今までの構文は、経験者にとってさえ往々にして曖昧にして難解で、代替機能を使うべきで本来お呼びでないような場面1で頻繁に使われ、時には遅く、代替機能にはできることができないのです。
その上、impl Trait
が入ったことで、「impl Trait
か dyn Trait
か」の関係はより対称的になり、「impl Trait
か Trait
か」よりちょっといい感じです。
impl Trait
の説明はこちらです。
したがって、新しいエディションでは、トレイトオブジェクトが必要なときは、ただの Trait
でなく dyn Trait
を使うべきです。
1 訳注: 原文ではこの文は、本ページで説明する新構文を提案する RFC から抜粋された文章になっています。 特に脚注で示した箇所は、原文では "favors a feature that is not more frequently used than its alternatives" とあり、その文意は同 RFC に解説されています。以下では、それを要約します。
特定のトレイトを実装した異なる型を共通して扱いたいとき、大抵はトレイトオブジェクトを使う必要はありません。 単一のコンテナに複数の型の構造体を入れたい場合、enum
を使えばよいです。 関数の返り値が特定のトレイトを実装していると示すには、impl Trait
構文を使えばよいです。 特定のトレイトを実装する任意の型を関数の引数や構造体のフィールドにした場合、ジェネリクスを使えばよいです。 大抵の場合は、このようにセマンティクス面からもパフォーマンス面からもより適切な代替案があり、トレイトオブジェクトの出る幕はありません。
トレイトオブジェクトが真に必要なのは、これより複雑なことをしたい場合だけです。 しかし、Rust 2015 では、&Trait
のように書くだけで、「気軽に」トレイトオブジェクトが作れてしまうという罠がありました。 そこで、Rust 2018 では、どうしてもトレイトオブジェクトを作りたい場合は&dyn Trait
構文を使用することが必要になりました。
async
と await
これらのキーワードは Rust に非同期の機能を実装するために予約されました。非同期の機能は最終的に 1.39.0 でリリースされました。
キーワード try
キーワード try
は try
ブロックで使うために予約されましたが、(これを書いている時点で)まだ安定化されていません(追跡イシュー)