W Rust można zaimplementować trait dla typu tylko jeśli:
Te zasady nazywane są orphan rule (zasada "osierocenia"). Chroni to przed konfliktami w przypadku niezależnych implementacji tego samego trait dla tego samego typu w różnych crate.
Jeśli chcesz zaimplementować zewnętrzny trait dla zewnętrznego typu — bezpośrednio to nie jest możliwe. Zazwyczaj stosuje się wzorzec "newtype": owinąć typ w swoją strukturę wewnątrz crate, a następnie zaimplementować trait dla własnego typu.
Przykład:
// Typ zewnętrzny i zewnętrzny trait (nie w naszym crate) // struct ExternalType; trait ExternalTrait { ... } struct MyWrapper(ExternalType); impl ExternalTrait for MyWrapper { /* ... */ } // Teraz pracujemy przez wrapper
Pytanie: Czy można zaimplementować zewnętrzny trait dla zewnętrznego typu, jeśli oba są publiczne, przez use i impl?
Niepoprawna odpowiedź: Tak, wystarczy po prostu zadeklarować impl w swoim crate, a wszystko będzie działać.
Poprawna odpowiedź: Nie, kompilator tego nie pozwoli. Pozwolenie na implementację trait jest możliwe tylko wtedy, gdy trait lub typ są zadeklarowane w bieżącym crate. W przeciwnym razie — błąd zasady osierocenia.
Przykład błędu:
// extern crate other; // impl Display for other::ExternalType { ... } // Błąd zasady osierocenia
Historia
Zespół potrzebował wsparcia zewnętrznego loggera przez impl zewnętrznego trait. Próba zaimplementowania go dla zewnętrznego typu zakończyła się błędem zasady osierocenia i długimi sporami o przyczyny. Ostatecznie trzeba było przeprojektować architekturę na newtype.
Historia
W projekcie open-source zdecydowano się zaimplementować Debug dla struktury z innej biblioteki, co zablokowało zasada osierocenia. W rezultacie użytkownicy musieli pracować z niewygodnymi obejściami i pisać własne opakowania.
Historia
Poważny błąd: podczas próby zaimplementowania FromStr dla zewnętrznego enum do analizy z ciągu, kompilator nie przepuścił zasady osierocenia. Programista "rozwiązał" problem za pomocą niebezpiecznych konwersji pamięci, co spowodowało UB w produkcji.