J'ai un tableau de taille inconnue, et j'aimerais obtenir une tranche de ce tableau et le convertir en tableau de taille statique:
fn pop(barry: &[u8]) -> [u8; 3] {
barry[0..3] // mismatched types: expected `[u8, ..3]` but found `&[u8]`
}
Comment je ferais ça?
Voici une fonction qui correspond à la signature de type que vous avez demandée.
fn pop(barry: &[u8]) -> [u8; 3] {
[barry[0], barry[1], barry[2]]
}
Mais comme barry
peut avoir moins de trois éléments, vous voudrez peut-être renvoyer un Option<[u8; 3]>
plutôt qu'un [u8; 3]
.
fn pop(barry: &[u8]) -> Option<[u8; 3]> {
if barry.len() < 3 {
None
} else {
Some([barry[0], barry[1], barry[2]])
}
}
Merci à @malbarbo nous pouvons utiliser cette fonction d'assistance:
use std::convert::AsMut;
fn clone_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Clone,
{
let mut a = Default::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
pour obtenir une syntaxe beaucoup plus propre:
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);
}
aussi longtemps que T: Default + Clone
.
Si vous savez que votre type implémente Copy
, vous pouvez utiliser ce formulaire:
use std::convert::AsMut;
fn copy_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Copy,
{
let mut a = Default::default();
<A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice);
a
}
Les deux variantes panic!
si le tableau cible et la tranche transmise n’ont pas la même longueur.
Je recommande d'utiliser crate arrayref , qui dispose d'une macro pratique pour le faire.
Notez qu'en utilisant cette caisse, vous créez une référence à un tableau, &[u8; 3]
, car il ne clone aucune donnée!
Si vous do voulez cloner les données, vous pouvez toujours utiliser la macro, mais appelez clone à la fin:
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> &[u8; 3] {
array_ref!(barry, 0, 3)
}
ou
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> [u8; 3] {
array_ref!(barry, 0, 3).clone()
}
Vous pouvez créer manuellement le tableau et le renvoyer.
Voici une fonction qui peut facilement évoluer si vous voulez obtenir plus de (ou moins) que 3 éléments.
Notez que si la tranche est trop petite, les termes de fin du tableau seront 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
}
Cette réponse utilise la fonctionnalité instable try_from
!
Vous pouvez facilement le faire avec le tout nouveau TryInto
trait (qui est toujours instable en juin 2018):
fn pop(barry: &[u8]) -> [u8; 3] {
barry.try_into()
.map(|s: &[u8; 3]| s.clone())
.expect("slice with incorrect length")
}
Mais encore mieux: il n’est pas nécessaire de cloner votre tableau! Il est effectivement possible d’obtenir un &[u8; 3]
à partir d’un &[u8]
:
fn pop(barry: &[u8]) -> &[u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
Comme mentionné dans les autres réponses, vous ne voudrez probablement pas paniquer si la longueur de barry
n'est pas 3, vous devriez donc renvoyer un Option<[u8; 3]>
ou quelque chose de similaire pour gérer cette erreur avec élégance.
Cela fonctionne grâce à ces impls (où $N
est juste un entier compris entre 1 et 32) du trait associé TryFrom
:
impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N]
type Error = TryFromSliceError;
Vous pouvez créer une macro personnalisée pour résoudre le problème . La contrainte ici, vous devez spécifier une taille de tranche constante. Vous ne pouvez pas créer de tableau de longueur dynamique, ce qui est expliqué à ces questions:
macro_rules! slice_to_array {
($x:expr, $size:expr) => {{
let mut array = [0; $size];
array.copy_from_slice(&$x[..$size]);
array
}};
}
fn main() {
let vec = vec![1i64, 2, 3, 4, 5, 7];
let array = slice_to_array!(vec, 4); // It works fine
// Attempt to use non-constant value in a constant
// let size = 4;
// let array = slice_to_array!(vec, size);
println!("{:?}", array);
}
Pour code de travail: terrain de jeu