簡體   English   中英

如何在 Rust 中將切片作為數組獲取?

[英]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兩者zipmap在一起,就像這樣簡單:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM