如何连接已知长度的数组?

fad*_*bee 6 arrays concatenation rust

我有两个已知长度的数组:

let left: [u8; 2] = [1, 2];
let right: [u8; 3] = [3, 4, 5];
Run Code Online (Sandbox Code Playgroud)

我的第一次尝试:

let whole: [u8; 5] = left + right;
Run Code Online (Sandbox Code Playgroud)

失败并出现错误:

error[E0369]: cannot add `[u8; 2]` to `[u8; 3]`
  --> /home/fadedbee/test.rs:25:29
   |
25 |         let whole: [u8; 5] = left + right;
   |                              ---- ^ ----- [u8; 3]
   |                              |
   |                              [u8; 2]
Run Code Online (Sandbox Code Playgroud)

同样地:

let whole: [u8; 5] = left.concat(right);
Run Code Online (Sandbox Code Playgroud)

失败:

error[E0599]: the method `concat` exists for array `[u8; 2]`, but its trait bounds were not satisfied
  --> /home/fadedbee/test.rs:25:29
   |
25 |         let whole: [u8; 5] = left.concat(right);
   |                                   ^^^^^^ method cannot be called on `[u8; 2]` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `<[u8] as std::slice::Concat<_>>::Output = _`
Run Code Online (Sandbox Code Playgroud)

我目前正在使用以下形式的表达式:

let whole: [u8; 5] = [left[0], left[1], right[0], right[1], right[2]];
Run Code Online (Sandbox Code Playgroud)

但这对于我的实际用例来说是几十个元素,并且容易出现拼写错误。

@Emoun 好心地指出我误用了concat.

正确尝试:

 let whole: [u8; 5] = [left, right].concat();
Run Code Online (Sandbox Code Playgroud)

我得到:

error[E0308]: mismatched types
  --> /home/fadedbee/test.rs:32:31
   |
32 |         let whole: [u8; 5] = [left, right].concat();
   |                                     ^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
   |
   = note: expected type `[u8; 2]`
             found array `[u8; 3]`
Run Code Online (Sandbox Code Playgroud)

如何将已知长度的数组连接成一个固定长度的数组?

yol*_*yer 7

我想有一个更好的答案,但你可以这样做:

fn main() {
    let left: [u8; 2] = [1, 2];
    let right: [u8; 3] = [3, 4, 5];

    let whole: [u8; 5] = {
        let mut whole: [u8; 5] = [0; 5];
        let (one, two) = whole.split_at_mut(left.len());
        one.copy_from_slice(&left);
        two.copy_from_slice(&right);
        whole
    };

    println!("{:?}", whole);
}
Run Code Online (Sandbox Code Playgroud)


Sve*_*ach 7

如果你想避免初始化目标数组的开销,你可以使用MaybeUninit()不安全的代码:

let a = [1, 2, 3];
let b = [4, 5];
let concatenated: [u8; 5] = unsafe {
    let mut result = std::mem::MaybeUninit::uninit();
    let dest = result.as_mut_ptr() as *mut u8;
    std::ptr::copy_nonoverlapping(a.as_ptr(), dest, a.len());
    std::ptr::copy_nonoverlapping(b.as_ptr(), dest.add(a.len()), b.len());
    result.assume_init()
};
Run Code Online (Sandbox Code Playgroud)

一旦 Rust 完全支持 const 泛型,就可以将此代码放入函数中。在 Nightly 上,现在已经可以使用以下generic_const_expr功能实现这一点:

#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

pub fn concat_arrays<T, const M: usize, const N: usize>(a: [T; M], b: [T; N]) -> [T; M + N] {
    let mut result = std::mem::MaybeUninit::uninit();
    let dest = result.as_mut_ptr() as *mut T;
    unsafe {
        std::ptr::copy_nonoverlapping(a.as_ptr(), dest, M);
        std::ptr::copy_nonoverlapping(b.as_ptr(), dest.add(M), N);
        std::mem::forget(a);
        std::mem::forget(b);
        result.assume_init()
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们不需要对 做任何假设T,因为所有 Rust 类型都可以通过按位复制来移动。