[英]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]`
}
我该怎么做?
您可以使用TryInto
特性(在 Rust 1.34 中稳定)轻松做到这一点:
use std::convert::TryInto;
fn pop(barry: &[u8]) -> [u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
但更好的是:无需克隆/复制您的元素! 实际上有可能得到一个&[u8; 3]
&[u8; 3]
来自&[u8]
:
fn pop(barry: &[u8]) -> &[u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
正如其他答案中提到的,如果barry
的长度不是 3,您可能不想惊慌,而是优雅地处理这个错误。
这要归功于相关特性TryFrom
这些实现(在 Rust 1.47 之前,这些仅存在于长度为 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]
感谢@malbarbo,我们可以使用这个辅助函数:
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
。
如果您知道您的类型实现了Copy
,则可以使用以下形式:
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!
如果目标数组和传入的切片长度不同。
这是一个与您要求的类型签名相匹配的函数。
fn pop(barry: &[u8]) -> [u8; 3] {
[barry[0], barry[1], barry[2]]
}
但是由于barry
元素可能少于三个,您可能需要返回一个Option<[u8; 3]>
Option<[u8; 3]>
而不是[u8; 3]
[u8; 3]
。
fn pop(barry: &[u8]) -> Option<[u8; 3]> {
if barry.len() < 3 {
None
} else {
Some([barry[0], barry[1], barry[2]])
}
}
我建议使用 crate arrayref ,它有一个方便的宏来执行此操作。
请注意,使用此 crate,您可以创建对数组的引用&[u8; 3]
&[u8; 3]
,因为它不会克隆任何数据!
如果您确实想克隆数据,那么您仍然可以使用宏,但在最后调用 clone:
#[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()
}
您可以手动创建数组并返回它。
如果您想获得多于(或少于)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
}
我对其他答案不满意,因为我需要几个函数来返回不同长度的固定 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>
Vec
、 'Slice' 和Array
之间的共同点是Iter
,因此您可以map
两者zip
和map
在一起,就像这样简单:
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);
这是因为数组是一维数组。
为了测试都在一起,VEC,切片和数组, 在这里你去:
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);
另一个应该比逐字节复制更快的选项是:
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.