创建对子切片的数组引用

Create array reference to sub slice

我有一片数据,想为固定大小的子片创建一个数组引用:

let slice: &[u8] = &[1, 2, 3, 4, 5];
let array_ref: &[u8; 2] = &slice[..2];

不幸的是,这不起作用,因为 &[..2] 的类型是 &[u8] 而不是 &[u8; 2]

我知道 <&[u8; 2]>::try_from(slice),但这会导致运行时检查,我更愿意使用不执行此运行时检查的 API,因为我知道在运行时大小要求是完成了。

是否有 API 允许这样做?

在这种情况下,当切片索引在 compile-time 可用时,try_from 将被优化掉。我们可以直接在 playground:

中查看
pub fn split_two(slice: &[u8]) -> &[u8; 2] {
    slice[..2].try_into().unwrap()
}

对应的程序集:

playground::split_two:
    cmpq    , %rsi
    jbe .LBB0_1
    movq    %rdi, %rax
    retq

.LBB0_1:
    pushq   %rax
    leaq    .L__unnamed_1(%rip), %rdx
    movl    , %edi
    callq   *core::slice::index::slice_end_index_len_fail@GOTPCREL(%rip)
    ud2

.L__unnamed_2:
    .ascii  "src/lib.rs"

.L__unnamed_1:
    .quad   .L__unnamed_2
    .asciz  "\n[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]2[=11=]0[=11=]0[=11=]0[=11=]5[=11=]0[=11=]0"

如您所见,这里唯一的检查是边界检查,即检查切片至少有两个元素长;但是没有检查子切片是否为两个元素长,因为这已经得到保证。

如果编译器可以看到切片长度足够,第一个检查也会被优化;示例:

// "extern" is used as an optimization barrier
extern "Rust" {
    fn use_ref(_: &[u8; 2]);
}

pub fn split_two(slice: &[u8; 5]) {
    let slice: &[u8] = slice;
    // `unsafe` is necessary to call `extern` function (even `extern "Rust"`)
    unsafe {
        use_ref(slice[..2].try_into().unwrap());
    }
}

编译为直接传递指针,根本没有任何检查:

playground::split_two:
    jmpq    *use_ref@GOTPCREL(%rip)