[英]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.