我有一个未知大小的数组,我想获得该数组的一部分并将其转换为静态大小的数组:
fn pop(barry: &[u8]) -> [u8; 3] {
barry[0..3] // mismatched types: expected `[u8, ..3]` but found `&[u8]`
}
我该怎么做?
答案 0 :(得分:17)
感谢@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!
。
答案 1 :(得分:15)
这是一个与您要求的类型签名相匹配的函数。
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]])
}
}
答案 2 :(得分:14)
您可以使用TryInto
特征(在Rust 1.34中稳定)轻松完成此操作:
fn pop(barry: &[u8]) -> [u8; 3] {
barry.try_into()
.map(|s: &[u8; 3]| s.clone())
.expect("slice with incorrect length")
}
但更好的是:没有必要克隆你的阵列!实际上可以从&[u8; 3]
获得&[u8]
:
fn pop(barry: &[u8]) -> &[u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
正如其他答案中所提到的,如果barry
的长度不是3,你可能不想恐慌,所以你应该返回一个Option<[u8; 3]>
或类似的东西来优雅地处理这个错误。
这要归功于相关特征TryFrom
的这些impl(其中$N
只是1到32之间的整数):
impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N]
type Error = TryFromSliceError;
答案 3 :(得分:13)
我建议使用crate arrayref,它有一个方便的宏来做这件事。
请注意,使用此包,您可以创建对数组&[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()
}
答案 4 :(得分:10)
您可以手动创建阵列并将其返回。
如果你想得到比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
}
答案 5 :(得分:1)
Vec
,'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);
这是因为数组是一维数组。
要一起测试vec,切片和阵列,请here进行测试:
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);
答案 6 :(得分:0)
您可以创建一个自定义宏来解决此问题。 在这里的约束,您必须将切片大小指定为常量。您无法创建具有动态长度的数组,对此问题进行了解释:
How to set a Rust array length dynamically?
Is it possible to have stack allocated arrays with the size determined at runtime in Rust?
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);
}
有关工作代码:playground
答案 7 :(得分:0)
我对其他答案不满意,因为我需要几个函数来返回可变长度的固定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>