循环中的可变借用

mutable borrows in a loop

我的代码:

struct Foo<'a> {
    bytes: &'a mut [u8],
}

impl<'a> Foo<'a> {
    fn bar<'b>(&'b mut self) {
        self.bytes = &mut self.bytes[1..];
    }
}

fn baz<'a, 'b>(foo: &'b mut Foo<'a>) {
    println!("baz!");
    
    for _ in 0..3 {
        foo.bar();
    }
}

还有here in a Rust Playground.

这会导致以下错误回溯:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:12:27
   |
12 |         self.bytes = &mut self.bytes[1..];
   |                           ^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'b` as defined here...
  --> src/main.rs:11:12
   |
11 |     fn bar<'b>(&'b mut self) {
   |            ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:12:27
   |
12 |         self.bytes = &mut self.bytes[1..];
   |                           ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/main.rs:10:6
   |
10 | impl<'a> Foo<'a> {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:12:22
   |
12 |         self.bytes = &mut self.bytes[1..];
   |                      ^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground` due to previous error

目标

我正在寻找更改 bar / baz 的函数签名以使其编译。我的理解是我需要在 'a'b 上指定生命周期界限并且它会起作用,但是我在 [=33= 中的 'b: 'a'a: 'b 得到不同的错误] 函数。

我还查看了大约 10 个其他“循环中的可变借用”问题,但我对答案的理解不够好,无法将它们应用到我的问题中,所以即使这是重复的,我也会很感激与这个玩具示例具体相关的答案。

感谢任何帮助!

这里的问题是通过 'b 发生借用。 ('b'a 是不相交的)。编译器希望您保证引用 'b 需要至少与 'a 一样长。因此,我们应该寻找一种在(重新)借用切片时不涉及 'b 的方法,因为 'b 被认为仅在函数调用期间有效。调用没有 return 或“传出”生命周期。

可以使用std::mem::*函数实现this

@vikram2784 的解决方案有效,但可以通过仅替换 bytes 而不是整个 Foo:

来更简洁地表达
impl<'a> Foo<'a> {
    fn bar(&mut self) {
        let tmp = &mut [][..];
        let bytes = std::mem::replace(&mut self.bytes, tmp);
        self.bytes = &mut bytes[1..];
    }
}

如果 Foo 包含一些没有明显默认值的附加字段,此模式也更易于使用。

关于这种解决方案需要注意的一点是:如果 bytes[1..] 崩溃,空的临时文件将留在原地。在这里,我能想到的恐慌的唯一原因就是bytes是空的,所以没关系,但根据情况,你可能会被它咬到。