如何在Rust中将切片作为数组?

Jer*_*oen 36 arrays rust

我有一个未知大小的数组,我想获得该数组的一部分并将其转换为静态大小的数组:

fn pop(barry: &[u8]) -> [u8; 3] {
    barry[0..3] // mismatched types: expected `[u8, ..3]` but found `&[u8]`
}
Run Code Online (Sandbox Code Playgroud)

我该怎么做?

Luk*_*odt 32

这个答案使用不稳定的TryInto功能!


您可以使用全新的&[u8; 3]特性(截至2018年6月仍然不稳定)轻松完成此操作:

fn pop(barry: &[u8]) -> [u8; 3] {
    barry.try_into().expect("slice with incorrect length")
}
Run Code Online (Sandbox Code Playgroud)

但更好的是:没有必要克隆你的阵列!实际上可以&[u8]从一个barry:

fn pop(barry: &[u8]) -> &[u8; 3] {
    barry.try_into().expect("slice with incorrect length")
}
Run Code Online (Sandbox Code Playgroud)

正如其他答案中所提到的,如果长度$N不是3 ,你可能不想恐慌,所以你应该返回一个TryFrom或类似的东西来优雅地处理这个错误.

这可以归功于TryInto相关特征的这些impl(其中只是1到32之间的整数)&[u8; 3]:

impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N]
  type Error = TryFromSliceError;

impl<'a, T: Copy> TryFrom<&'a [T]> for [T; $N]
  type Error = TryFromSliceError;
Run Code Online (Sandbox Code Playgroud)

  • 现在`impl&lt;'a, T&gt; TryFrom&lt;&amp;'a [T]&gt; for [T; $N] 其中还提供了 T: Copy`(`[T; $N]` 与 `&amp;'a [T; $N]`)。 (2认同)

Mat*_* M. 18

感谢@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
}
Run Code Online (Sandbox Code Playgroud)

获得更整洁的语法:

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);
}
Run Code Online (Sandbox Code Playgroud)

只要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
}
Run Code Online (Sandbox Code Playgroud)

panic!如果目标数组和传入的切片不具有相同的长度,则两种变体都将成立.

  • 在“ let mut a = Default :: default();”行中是否应该是“ let mut a = A :: default();”? (2认同)

mwh*_*ker 15

这是一个与您要求的类型签名相匹配的函数.

fn pop(barry: &[u8]) -> [u8; 3] {
    [barry[0], barry[1], barry[2]]
}
Run Code Online (Sandbox Code Playgroud)

但由于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]])
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 1 1,因为没有解决一般情况(例如[[u8; 32]];没人会重复索引32次) (6认同)
  • 更新:const 泛型已稳定;) (3认同)
  • @diralik 然而有人这样做......在 const 泛型稳定之前,这仍然是最好的方法。当前的 rust std 确实有一个不稳定的特征,可以确保数组长度达到 32,然后实现大多数对每个单个数组类型实现最多 32 次有意义的特征......这就是现在的现实。您可以编写代码生成器,随意输出 0 到 N 数组代码,以使其更好一些,这个答案很好,并展示了 std 是如何做到的。或者你只是想对大小为 33 的数组说“运气不好,5 年后见”? (2认同)

pah*_*olg 14

我建议使用crate arrayref,它有一个方便的宏来做这件事.

请注意,使用此包,您可以创建对数组的引用&[u8; 3],因为它不会克隆任何数据!

如果您确实要克隆数据,那么您仍然可以使用宏,但最后调用clone:

#[macro_use]
extern crate arrayref;

fn pop(barry: &[u8]) -> &[u8; 3] {
    array_ref!(barry, 0, 3)
}
Run Code Online (Sandbox Code Playgroud)

要么

#[macro_use]
extern crate arrayref;

fn pop(barry: &[u8]) -> [u8; 3] {
    array_ref!(barry, 0, 3).clone()
}
Run Code Online (Sandbox Code Playgroud)


Lev*_*ans 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
}
Run Code Online (Sandbox Code Playgroud)