2014-06-21 4 views
5

voglio fornire un'implementazione di un tratto ToHex (non definito da me, da serialize) per un tipo primitivo u8:Fornire un'implementazione quando entrambi tratto e tipo non sono in questa cassa

impl ToHex for u8 { 
    fn to_hex(&self) -> String { 
     self.to_str_radix(16) 
    } 
} 

Il problema è ottengo questo errore di compilazione:

error: cannot provide an extension implementation where both trait and type are not defined in this crate 

capisco il motivo di questo errore e la sua logica, questo è perché sia ​​il tratto e il tipo primitivo sono esterni al mio codice. Ma come posso gestire questa situazione e fornire un'implementazione ToHex per u8? E più in generale come gestisci questo tipo di problema, mi sembra che questo problema debba essere comune e dovrebbe essere possibile e facile estendere tipi come questo?

risposta

10

Si consiglia di utilizzare una struttura newtype per fare questo:

pub struct U8(pub u8) 

impl ToHex for U8 { 
    fn to_hex(&self) -> String { 
     let U8(x) = *self; 
     x.to_str_radix(16) 
    } 
} 

Ciò significa, tuttavia, che si dovrebbe avvolgere u8 in U8 in cui è necessario eseguire questa conversione:

let x: u8 = 127u8 

// println!("{}", x.to_hex()); // does not compile 
println!("{}", U8(x).to_hex()); 

Questo è assolutamente gratuito in termini di prestazioni.

+0

È un bel trucco che tu proponi. Ma nel mio caso mi preoccupo che sarebbe un po 'troppo ingombrante per avvolgere tutti i tipi primitivi che uso in quel modo. – user3762625

+3

@ user3762625, non è un hack, è in effetti l'unico metodo possibile. Non è possibile aggiungere implementazioni tratto di tratti che non possiedi a tipi che non possiedi, e non c'è soluzione alternativa ma newtypes. –

+0

@ user3762625: Beh, nel caso presentato, sarebbe più semplice avere una funzione libera 'to_hex' per' u8' direttamente (che è possibile definire); hai solo bisogno di avvolgere quando devi passare un 'u8' dove è previsto' ToHex'. –

3

Mi rendo conto che è quasi un anno, ma la risposta non è mai stata accettata e penso di aver trovato una soluzione alternativa, che ho pensato sarebbe stato utile per documentare qui.

Al fine di estendere le funzionalità del U8 attraverso tratti, invece di cercare di estendere ToHex, perché non creare un nuovo tratto?

trait MyToHex { 
    fn to_hex(&self) -> String; 
} 

impl MyToHex for u8 { 
    fn to_hex(&self) -> String { 
     format!("{:x}", *self) 
    } 
} 

poi utilizzato in questo modo

fn main() { 
    println!("{}", (16).to_hex()); 
} 

Questo ha il vantaggio che non si dispone di avvolgere ogni U8 variabile con un nuovo e superfluo tipo di dati.

Lo svantaggio è che non è ancora possibile utilizzare un U8 in una funzione esterna (cioè libreria std, o quello che hai alcun controllo su) che richiede l'ToHex tratto (soluzione di Vladimir Matveev funziona in questo caso), ma da OP sembra che tutto ciò che si vuole fare sia estendere u8 solo all'interno del proprio codice.

Problemi correlati