创建对子切片的数组引用
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)
我有一片数据,想为固定大小的子片创建一个数组引用:
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)