可以通过可变引用“推进”可变切片吗?

6

我经常使用共享切片来做这样的事情:

fn read_a_few_bytes(slice: &mut &[u8]) {
    dbg!(&slice[..3]);
    *slice = &slice[3..];
}

今天我注意到,当切片是可变的时,那种方法不起作用:
fn read_a_few_bytes(slice: &mut &mut [u8]) {
    dbg!(&slice[..3]);
    *slice = &mut slice[3..];
}

第二个例子会出现以下错误:
error: lifetime may not live long enough
 --> src/main.rs:3:5
  |
1 | fn read_a_few_bytes(slice: &mut &mut [u8]) {
  |                            -    - let's call the lifetime of this reference `'2`
  |                            |
  |                            let's call the lifetime of this reference `'1`
2 |     dbg!(&slice[..3]);
3 |     *slice = &mut slice[3..];
  |     ^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`

这是借用检查器的限制吗?还是我在尝试做的事情实际上是不安全的?有什么解决方法吗?

无论如何,您都不能有超过一个可变引用指向同一事物。另外,双重mut指针是C中的经典问题(在C中是为const,但无论如何都是同样的问题)。因此,在Rust中您不能这样做。 - Stargateur
rustc 1.69 的建议更改函数签名为 fn read_a_few_bytes<'a>(slice: &'a mut &'a mut [u8]) {},这个额外的生命周期参数 'a 可以锁定所有变量以防止生命周期不匹配,这是你想要的吗? - metatoaster
1
也许值得使用完全限定的语法将表达式写出来,以便更清楚地了解发生了什么?诚然,我尝试过,但仍然感到困惑。也许你能看到我看不到的东西。顺带一提,我很喜欢你的 Rust 视频;我是你的忠实粉丝。 - cyqsimon
@metatoaster,它可以编译,但我不确定实际上它是否非常有用。我没想到Rust会接受这个。另一种选择是fn read_a_few_bytes<'a, 'b: 'a>(slice: &'b mut &'a mut [u8]) - Stargateur
@metatoaster 如果你遵循编译器的建议,你会得到一个只能工作一次的函数,但是它会永久地借用切片,你无法再次调用它。如果你使用两个生命周期参数,同样的事情也会发生。 - Jack O'Connor
啊,谢谢你提供的关于为什么那个建议不太有用的背景信息。 - metatoaster
1个回答

6
你可以使用 std::mem::take 来解决这个问题。
fn read_a_few_bytes(slice: &mut &mut [u8]) {
    let data = std::mem::take(slice);
    *slice = &mut data[3..];
}

1
参考文献,这是不稳定的 take*_mut 函数的作用 https://doc.rust-lang.org/src/core/slice/mod.rs.html#4091 - drewtato
谢谢!令人惊叹的是,你可以为任何类型 T 和任何生命周期构建一个空的 &mut [T] 并进行交换。 - Jack O'Connor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接