我有一个大小未知的数组,我想要获取该数组的一个切片并将其转换为静态大小的数组:
fn pop(barry: &[u8]) -> [u8; 3] {
barry[0..3] // expected array `[u8; 3]`, found slice `[u8]`
}
我该如何做到这一点?
TryInto
trait来实现这一点:// 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")
}
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]
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!
let mut a = Default::default();
中,可能应该改为 let mut a = A::default();
,对吗? - Constantine<A as Default>::default()
是另一种变体。 - Matthieu M.A::default()
,因为它更加明确。 - Jocelyn我建议使用 arrayref 这个 crate,它有一个很方便的宏可以做到这一点。
请注意,使用此 crate,您将创建一个对数组的引用,&[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()
}
这里是一个符合你要求的类型签名的函数。
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]])
}
}
[u8; 32]
;没有人会重复使用 32 次索引访问)你可以手动创建数组并返回它。
以下是一个函数,如果你想要获取超过3个元素或者少于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
类型,则需要为每种类型定义函数会变得很烦人。 - ideasman42我不满意其他答案,因为我需要返回长度不同的定长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>
return
不是惯用语。 - ShepmasterVec
、'Slice'和Array
之间的共同点是Iter
,因此您可以像这样简单地同时使用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);
这是因为数组是一维数组。
为了同时测试向量、切片和数组,请参考此处:
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);
impl<'a, T> TryFrom<&'a [T]> for [T; $N] where T: Copy
也已经提供了(与&'a [T; $N]
相比)。 - updogliuVec
:<[i32; 2]>::try_from(&vec[..])
。 - cambunctiouschunks_exact
时有一个保证。 - Jorge Leitaouse std::convert::TryInto;
在2021版中似乎不再需要了:https://doc.rust-lang.org/std/prelude/index.html - jaques-sam