Come ottenere una fetta come matrice in Rust?

Ho una matrice di una dimensione sconosciuta, e mi piacerebbe avere una porzione di quella matrice e convertirla in una matrice di dimensioni statiche:

fn pop(barry: &[u8]) -> [u8; 3] { barry[0..3] // mismatched types: expected `[u8, ..3]` but found `&[u8]` } 

Come lo farei?

Ecco una funzione che corrisponde alla firma del tipo che hai richiesto.

 fn pop(barry: &[u8]) -> [u8; 3] { [barry[0], barry[1], barry[2]] } 

Ma dal momento che barry potrebbe avere meno di tre elementi, potresti voler restituire Option< [u8; 3]> Option< [u8; 3]> piuttosto che a [u8; 3] [u8; 3] .

 fn pop(barry: &[u8]) -> Option< [u8; 3]> { if barry.len() < 3 { None } else { Some([barry[0], barry[1], barry[2]]) } } 

Grazie a @malbarbo possiamo usare questa funzione di aiuto:

 use std::convert::AsMut; fn clone_into_array(slice: &[T]) -> A where A: Default + AsMut< [T]>, T: Clone, { let mut a = Default::default(); >::as_mut(&mut a).clone_from_slice(slice); a } 

per ottenere una syntax molto più ordinata:

 fn main() { let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let e = Example { a: clone_into_array(&original[0..4]), b: clone_into_array(&original[4..10]), }; println!("{:?}", e); } 

finché T: Default + Clone .

Se conosci il tuo tipo implementa Copy , puoi utilizzare questo modulo:

 use std::convert::AsMut; fn copy_into_array(slice: &[T]) -> A where A: Default + AsMut< [T]>, T: Copy, { let mut a = Default::default(); >::as_mut(&mut a).copy_from_slice(slice); a } 

Entrambe le varianti andranno nel panic! se l’array di destinazione e la slice passata non hanno la stessa lunghezza.

Vi consiglio di usare l’ arrayref della cassa, che ha una macro utile per fare proprio questo.

Nota che, usando questa cassa, crei un riferimento a un array, &[u8; 3] &[u8; 3] , perché non clona alcun dato!

Se vuoi clonare i dati, puoi comunque utilizzare la macro, ma alla fine clona la chiamata:

 #[macro_use] extern crate arrayref; fn pop(barry: &[u8]) -> &[u8; 3] { array_ref!(barry, 0, 3) } 

o

 #[macro_use] extern crate arrayref; fn pop(barry: &[u8]) -> [u8; 3] { array_ref!(barry, 0, 3).clone() } 

È ansible creare manualmente la matrice e restituirla.

Ecco una funzione che può essere facilmente ridimensionata se si desidera ottenere più (o meno) di 3 elementi.

Nota che se la sezione è troppo piccola, i termini finali dell’array saranno 0.

 fn pop(barry: &[u8]) -> [u8; 3] { let mut array = [0u8; 3]; for (&x, p) in barry.iter().zip(array.iter_mut()) { *p = x; } array } 

Questa risposta utilizza la funzione try_from instabile!


Puoi farlo facilmente con il nuovissimo tratto TryInto (che è ancora instabile a partire dal giugno 2018):

 fn pop(barry: &[u8]) -> [u8; 3] { barry.try_into() .map(|s: &[u8; 3]| s.clone()) .expect("slice with incorrect length") } 

Ma ancora meglio: non è necessario clonare il tuo array! In realtà è ansible ottenere un &[u8; 3] &[u8; 3] da un &[u8] :

 fn pop(barry: &[u8]) -> &[u8; 3] { barry.try_into().expect("slice with incorrect length") } 

Come menzionato nelle altre risposte, probabilmente non vorrai andare nel panico se la lunghezza di barry non è 3, quindi dovresti restituire Option< [u8; 3]> Option< [u8; 3]> o qualcosa di simile per gestire questo errore con garbo.

Questo funziona grazie a questi impls (dove $N è solo un numero intero compreso tra 1 e 32) del tratto relativo TryFrom :

 impl< 'a, T> TryFrom< &'a [T]> for &'a [T; $N] type Error = TryFromSliceError;