如何在Rust中缩短数组

h6my8fg2  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(81)

如何有效实施:

fn shorten(arg: [u8; 32]) -> [u8; 30] {
    ???
}

丢弃最后两个字节
显然,我可以使用for循环,并在堆栈上创建一个新的更短的数组。
编译器似乎有机会将[u8; 32]留在堆栈上,只使用它的[u8; 30]
通常我会使用切片,但这里我需要返回一个更短的数组。

n1bvdmb6

n1bvdmb61#

这是其中一个问题,直接的答案并不真正有价值。但让我们从直接的答案开始:您可以将该函数实现为

fn shorten(arg: [u8; 32]) -> [u8; 30] {
    std::array::from_fn(|i| arg[i])
}
// or
fn shorten(arg: [u8; 32]) -> [u8; 30] {
    arg[..30].try_into().unwrap()
}
// or
fn shorten(arg: [u8; 32]) -> [u8; 30] {
    let mut ret = [0; 30];
    ret.copy_from_slice(&arg[..30]);
    ret
}
// or
fn shorten(arg: [u8; 32]) -> [u8; 30] {
    let mut ret = [0; 30];
    for i in 0..30 {
        ret[i] = arg[i];
    }
    ret
}

忽略函数调用的脚手架,这些都优化到四个x86指令。

movups  xmm0, xmmword ptr [rsi]
movups  xmm1, xmmword ptr [rsi + 14]
movups  xmmword ptr [rdi + 14], xmm1
movups  xmmword ptr [rdi], xmm0

(See这里的技巧,与重叠的加载/存储?聪明. -.-)godbolt
现在,对于答案的不直接部分:问题是,孤立地看待fn shorten是没有意义的:

  • 只要shorten是它自己的函数,并且返回一个拥有的[u8; 30],它就必须复制一个副本,因为返回值是一个独立于参数的值。它不能返回指向参数的指针,因为签名承诺它返回一个值。
  • shorten很短,LLVM肯定会内联它。接下来的问题是LLVM是否可以弄清楚,无论使用shorten的结果是什么,它也会对[u8; 32]感到满意。它是否能做到这一点并不能用你提供的信息来回答。

最后,shorten是四个x86指令。你真的在这一点上吃了很大一部分你的执行时间?

相关问题