How to get a slice as an array in Rust?

我有一个未知大小的数组,我想得到该数组的一个片段,并将其转换为静态大小的数组:

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

我要怎么做?

93061 次浏览

Here's a function that matches the type signature you asked for.

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

但是由于 barry可以少于三个元素,您可能希望返回一个 Option<[u8; 3]>而不是 [u8; 3]

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

您可以手动创建数组并返回它。

如果您想获得多于(或少于)3个元素,这里有一个函数可以很容易地进行伸缩。

注意,如果切片太小,数组的结束项将是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
}

感谢 @ malbarbo,我们可以使用这个 helper 函数:

use std::convert::AsMut;


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

为了得到一个更简洁的语法:

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

只要 T: Default + Clone

If you know your type implements Copy, you can use this form:

use std::convert::AsMut;


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

如果目标数组和传入的片的长度不相同,那么这两个变量都将 panic!

我建议使用箱 Arrayref,它有一个方便的宏来完成这项工作。

注意,使用这个板条箱,可以创建对数组 &[u8; 3]的引用,因为它不克隆任何数据!

If you want to clone the data, then you can still use the macro, but call clone at the end:

#[macro_use]
extern crate arrayref;


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

或者

#[macro_use]
extern crate arrayref;


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

你可以很容易地用 TryInto特性(在锈病1.34中稳定)来做到这一点:

// Before Rust 2021, you need to import the trait:
// use std::convert::TryInto;


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

但是更好的是: 没有必要克隆/复制您的元素!从 &[u8]中获得 &[u8; 3]实际上是可能的:

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

As mentioned in the other answers, you probably don't want to panic if the length of barry is not 3, but instead handle this error gracefully.

This works thanks to these impls of the related trait TryFrom (before Rust 1.47, these only existed for arrays up to length 32):

impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N]
where
T: Copy,


impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]


impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]

我对其他答案不满意,因为我需要几个函数返回不同长度的固定 u8数组。我编写了一个生成特定于任务的函数的宏。希望能帮到别人。

#[macro_export]
macro_rules! vec_arr_func {
($name:ident, $type:ty, $size:expr) => {
pub fn $name(data: std::vec::Vec<$type>) -> [$type; $size] {
let mut arr = [0; $size];
arr.copy_from_slice(&data[0..$size]);
arr
}
};
}


//usage - pass in a name for the fn, type of array, length
vec_arr_func!(v32, u8, 32);
v32(data); //where data is std::vec::Vec<u8>

The nice common thing between Vec, 'Slice' and Array is Iter, so you can zip and map both together, as simple as:

let x = vec![1, 2, 3];
let mut y: [u8; 3] = [Default::default(); 3];
println!("y at startup: {:?}", y);
x.iter().zip(y.iter_mut()).map(|(&x, y)| *y = x).count();
println!("y copied from vec: {:?}", y);

enter image description here

这是因为数组是一维数组。

要测试所有的元素,vec,cut 和 array,给你需要这样做:

let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
let mut x: Vec<u8> = vec![Default::default(); 3];
println!("X at startup: {:?}", x);
slice.iter().zip(x.iter_mut()).map(|(&s, x)| *x = s).count();
println!("X copied from vec: {:?}", x);

enter image description here

Another option which should be faster than byte-by-byte copy is:

y[..x.len()].copy_from_slice(&x);

这对所有人都适用,下面是一个例子:

let a = [1, 2, 3, 4, 5];
let mut b: Vec<u8> = vec![Default::default(); 5];
b[..a.len()].copy_from_slice(&a);
println!("Copy array a into vector b: {:?}", b);


let x: Vec<u8> = vec![1, 2, 3, 4, 5];
let mut y: [u8; 5] = [Default::default(); 5];
y[..x.len()].copy_from_slice(&x);
println!("Copy vector x into array y: {:?}", y);

enter image description here