Wie bekommt man eine Scheibe in Rust?

Ich habe ein Array unbekannter Größe, und ich möchte ein Stück dieses Arrays erhalten und es in ein Array von statischer Größe konvertieren:

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

Wie würde ich das tun?

   

Hier ist eine function, die der gesuchten Typensignatur entspricht.

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

Da barry jedoch weniger als drei Elemente haben kann, möchten Sie vielleicht eine Option< [u8; 3]> Option< [u8; 3]> anstatt 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]]) } } 

Dank @malbarbo können wir diese Hilfsfunktion nutzen:

 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 } 

um eine viel bessere Syntax zu erhalten:

 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); } 

solange T: Default + Clone .

Wenn Sie wissen, dass Ihr Typ Copy implementiert, können Sie dieses Formular verwenden:

 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 } 

Beide Varianten werden in panic! wenn das Zielarray und die übergebene Scheibe nicht die gleiche Länge haben.

Ich empfehle, die Kiste arrayref zu verwenden , die ein handliches Makro hat, um genau dies zu tun.

Beachten Sie, dass Sie mit dieser Kiste einen Verweis auf ein Array erstellen, &[u8; 3] &[u8; 3] , weil es keine Daten klont!

Wenn Sie die Daten klonen möchten, können Sie immer noch das Makro verwenden, aber Clone am Ende aufrufen:

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

oder

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

Sie können das Array manuell erstellen und es zurückgeben.

Hier ist eine function, die leicht skaliert werden kann, wenn Sie mehr (oder weniger) als 3 Elemente erhalten möchten.

Beachten Sie, dass die Endbedingungen des Arrays Nullen sind, wenn das Segment zu klein ist.

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

Diese Antwort verwendet die instabile function try_from !


Das können Sie ganz einfach mit der brandneuen TryInto Eigenschaft TryInto (die im Juni 2018 noch instabil ist):

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

Aber noch besser: Sie brauchen Ihr Array nicht zu klonen! Es ist tatsächlich möglich, ein &[u8; 3] &[u8; 3] von einem &[u8] :

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

Wie in den anderen Antworten erwähnt, möchten Sie wahrscheinlich nicht in Panik geraten, wenn die Länge von barry nicht 3 ist, also sollten Sie eine Option< [u8; 3]> Option< [u8; 3]> oder etwas Ähnliches, um diesen Fehler elegant zu behandeln.

Dies funktioniert dank dieser Impls (wobei $N nur eine ganze Zahl zwischen 1 und 32 ist) des verwandten Merkmals TryFrom :

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