Rust では、型に対して trait を実装することは、以下の条件を満たす場合にのみ許可されます:
これらの条件を孤児ルール (orphan rule) と呼びます。これは、異なる crate で同じ型に対して同じ trait の独立した実装が衝突するのを防ぐためのものです。
外部型に対して外部の trait を実装したい場合は、直接それを行うことはできません。通常は「newtype」パターンを使用します:型を自分の構造体の中にラップし、その後自分の型に対して trait を実装します。
例:
// 外部型と外部 trait (私たちの crate にはない) // struct ExternalType; trait ExternalTrait { ... } struct MyWrapper(ExternalType); impl ExternalTrait for MyWrapper { /* ... */ } // これでラッパーを介して作業します
質問: 両方が公開されている場合、use と impl を通じて外部の trait を外部の型に対して実装できますか?
誤った答え: はい、単に自分の crate で impl を宣言すれば、すべてが機能します。
正しい答え: いいえ、コンパイラはそれを許可しません。trait または型が現在の crate で宣言されている場合にのみ trait を実装することが許可されます。そうでない場合は孤児ルールエラーになります。
エラーの例:
// extern crate other; // impl Display for other::ExternalType { ... } // 孤児ルールエラー
ストーリー
チームでは、外部のロガーを impl を通じてサポートする必要がありました。外部型に対してそれを実装しようとしたところ、孤児ルールエラーが発生し、その理由についての長い議論がありました。最終的には newtype を使用してアーキテクチャを再設計せざるを得ませんでした。
ストーリー
オープンソースプロジェクトで、別のライブラリの構造体に対して Debug を実装することを決定しましたが、孤児ルールによりそれが不可能でした。その結果、ユーザーは不便な workaround を利用せざるを得ず、自分のラッパーを作成する必要がありました。
ストーリー
重大なバグ: 外部の enum に対して FromStr を実装しようとした際、コンパイラが孤児ルールを通過させませんでした。開発者は安全でないメモリ変換によって問題を「解決」し、その結果、プロダクションで未定義の動作が発生しました。