2015-06-15 14 views
5

Sto cercando di imparare Rust e ho deciso di scrivere un programma che converta una stringa esadecimale in un u64.Qual è il modo più appropriato per convertire i nibbles in un u64?

Attualmente, ho analizzato la stringa in un vettore di valori u8, ciascuno rappresentante quattro bit (o "nibble"). Ho scritto il seguente codice per prendere uno Vec<u8> e restituire uno u64 corrispondente. Funziona (per quanto riguarda i miei test), ma non sono sicuro che sia il modo "appropriato" in Rust per fare questo.

fn convert_nibbles_to_u64(values: &Vec<u8>) -> u64 { 
    // We need to turn this buffer into a u64 now 
    let mut temp:u64 = 0; 
    for i in values { 
     temp = temp << 4; 

     unsafe { 
      // We need to unsafely convert a u8 to a u64. Note that 
      // the host endian-ness will matter here. 
      use std::mem; 
      let i_64_buffer = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,i.clone()]; 
      let i_64 = mem::transmute::<[u8; 8], u64>(i_64_buffer); 
      let i_64_be = u64::from_be(i_64); 
      temp = temp | i_64_be;   
     } 
    } 
    return temp; 
} 

Suppongo che il problema principale non so in quale altro modo per lanciare un u8 ad un valore u64. Potresti commentare i modi per migliorare o scrivere il codice in uno stile più idiomatico e simile alla Ruggine?

EDIT: Ho provato le seguenti alternative (falliti) al blocco pericoloso:

Or'ing con i come u64:

temp = temp | i as u64; 
------ 
Compiler error: 
main.rs:115:23: 115:31 error: non-scalar cast: `&u8` as `u64` 
main.rs:115   temp = temp | i as u64; 

Or'ing con i direttamente:

temp = temp | i; 
------ 
Compiler error: 
main.rs:115:16: 115:24 error: the trait `core::ops::BitOr<&u8>` is not implemented for the type `u64` [E0277] 
main.rs:115   temp = temp | i; 
+0

Cosa c'è di sbagliato con 'i come u64'? –

+0

Quindi, da ogni 'u8' stai usando solo quattro bit. Quindi se i tuoi bit sono '[0b0000AAAA, 0b0000BBBB, 0b0000CCCC, 0b0000DDDD, 0b0000EEEE, 0b0000FFFF, 0b0000GGGG, 0b0000HHHH]' stai per finire con '0bAAAABBBBCCCCDDDDEEEEFFFFGGGHHHHu64'. Ho ragione? –

+0

@ChrisMorgan se l'input è [0xF, 0xE, 0xE, 0xD, 0xB, 0xE, 0xE, 0xF, 0xF, 0xE, 0xE, 0xD, 0xB, 0xE, 0xE, 0xF], l'output deve essere 0xFEEDBEEFFEEDBEEFu64. – samoz

risposta

7

Il tuo problema è semplice: for i in values, dove values è di tipo &Vec<u8>, itera su riferimenti a ciascun valore; ovvero, i è di tipo &u8. Oring e aggiunta e tali con riferimenti non hanno senso; devi dereferenziarlo, ottenendo il sottostante u8. Il modo più semplice di fare questo sta scrivendo in modello della for del loop (per la grammatica for è for PATTERN in EXPRESSION, consultare la documentazione sui modelli maggiori spiegazioni se ne avete bisogno, per questo semplice caso, for &x in y { … } significa fondamentalmente for x in y { let x = *x; … }):

fn convert_nibbles_to_u64(values: &[u8]) -> u64 { 
    let mut out = 0; 
    for &i in values { 
     out = out << 4 | i as u64; 
    } 
    out 
} 

tutta la forma di un anello può essere crollata con Iterator.fold, anche, in questo modo:

fn convert_nibbles_to_u64(values: &[u8]) -> u64 { 
    values.iter().fold(0, |x, &i| x << 4 | i as u64) 
} 
+0

Wow così semplice, grazie per il tuo aiuto! Questo è esattamente il motivo per cui pubblico su SO quando apprendo una nuova lingua. "Stai facendo qualcosa che nessuno fa mai, smettila." Funziona come un fascino, grazie a @ChrisMorgan! – samoz

Problemi correlati