ProgrammazioneSviluppatore Rust, Designer di API/Librerie

Spiega come funziona il system of traits in Rust quando si lavora con tipi esterni (orphan rule). Come implementare un trait per un tipo dichiarato da altri e perché non è sempre possibile?

Supera i colloqui con l'assistente IA Hintsage

Risposta

In Rust, è consentito implementare un trait per un tipo solo se:

  • il trait è dichiarato nel crate attuale OPPURE
  • il tipo è dichiarato nel crate attuale

Queste condizioni sono chiamate orphan rule (regola "orfana"). Ciò protegge dai conflitti in caso di implementazioni indipendenti dello stesso trait per lo stesso tipo in diversi crate.

Se desideri implementare un trait esterno per un tipo esterno, non è possibile farlo direttamente. Di solito si utilizza il pattern "newtype": avvolgere il tipo in una struttura propria all'interno del crate e poi implementare il trait per il proprio tipo.

Esempio:

// Tipo esterno e trait esterno (non nel nostro crate) // struct ExternalType; trait ExternalTrait { ... } struct MyWrapper(ExternalType); impl ExternalTrait for MyWrapper { /* ... */ } // Ora lavoriamo attraverso l'involucro

Domanda trabocchetto

Domanda: È possibile implementare un trait esterno per un tipo esterno, se entrambi sono pubblici, tramite use e impl?

Risposta errata: Sì, basta semplicemente dichiarare impl nel proprio crate e tutto funzionerà.

Risposta corretta: No, il compilatore non lo consentirà. È possibile implementare un trait solo se il trait o il tipo sono dichiarati nel crate attuale. In caso contrario, si verifica un errore della orphan rule.

Esempio di errore:

// extern crate other; // impl Display for other::ExternalType { ... } // Errore orphan rule

Esempi di errori reali dovuti alla mancanza di conoscenza delle sottigliezze dell'argomento


Storia

Nel team è stata necessaria la supporto di un logger esterno tramite impl di un trait esterno. Il tentativo di implementarlo per un tipo di terze parti ha portato a un errore della orphan rule e a lunghe discussioni sulle cause. Alla fine, è stato necessario riprogettare l'architettura secondo il newtype.


Storia

In un progetto open-source, si è deciso di implementare Debug per una struttura di un'altra libreria, cosa che non ha permesso la orphan rule. Di conseguenza, gli utenti sono stati costretti a lavorare con workaround scomodi e a scrivere le proprie involucri.


Storia

Grave bug: nel tentativo di implementare FromStr per un enum esterno per l'analisi da stringa, il compilatore ha bloccato la orphan rule. Lo sviluppatore ha "risolto" il problema tramite conversioni unsafe in memoria, il che ha portato a UB in produzione.