rust - 为什么从 `&' a [u8 ]` to ` &'a mut [u8]` 更改字段会导致生命周期错误?

标签 rust

此代码编译:

struct BufRef<'a> {
    buf: &'a [u8],
}

struct Foo<'a> {
    buf_ref: BufRef<'a>,
}

impl<'a> Iterator for Foo<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        let result = &self.buf_ref.buf;
        Some(result)
    }
}

但是,如果我将 BufRef 更改为:

struct BufRef<'a> {
    buf: &'a mut [u8],
}

编译器说:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src\main.rs:13:16
   |
13 |         let result = &self.buf_ref.buf;
   |                      ^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
  --> src\main.rs:12:5
   |
12 | /     fn next(&mut self) -> Option<Self::Item> {
13 | |         let result = &self.buf_ref.buf;
14 | |         Some(result)
15 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src\main.rs:13:16
   |
13 |         let result = &self.buf_ref.buf;
   |                      ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 9:6...
  --> src\main.rs:9:6
   |
9  | impl<'a> Iterator for Foo<'a> {
   |      ^^
   = note: ...so that the types are compatible:
           expected std::iter::Iterator
              found std::iter::Iterator

为什么将字段更改为&'a mut [u8]会导致错误?

另外,编译器是什么意思:

...so that the types are compatible:
               expected std::iter::Iterator
                  found std::iter::Iterator

最佳答案

我认为误导您的是您的代码具有折叠引用。

您的 next 函数基本上等同于此代码:

fn next(&mut self) -> Option<&'a [u8]> {
    let result: &&'a [u8] = &self.buf_ref.buf;
    Some(result)
}

之所以可行,是因为双重引用折叠为单个引用。在这种情况下,双重引用只会混淆代码。只写:

fn next(&mut self) -> Option<Self::Item> {
    Some(self.buf_ref.buf)
}

这是可行的,因为引用总是Copy

但是当您将定义更改为 &'a mut 时会发生什么?您现在可能正在猜测...可变引用不是 Copy,因此相同的简单代码会给您一个易于阅读的错误消息:

cannot move out of self.buf_ref.buf which is behind a mutable reference

自然地,您可以将可变引用重新借用为常量引用,然后尝试归还它,但不幸的是,这行不通,因为重新借用不能使用与可变变量相同的生命周期,它必须严格小于(或者您可以为指向的值起别名)。编译器将此重新借用的生命周期分配为 next 函数的生命周期,但现在您无法返回此借用,因为它是本地引用!

不幸的是,我不知道有什么安全的方法可以编译您的代码。事实上,我很确定它会创建一个不可靠的 API。也就是说,如果您设法编译了您的代码,那么这段安全代码将产生未定义的行为:

fn main() {
    let mut buf = vec![1,2,3];
    let buf_ref = BufRef { buf: &mut buf };
    let mut foo = Foo { buf_ref };
    let x: &[u8] = foo.next().unwrap();
    //note that x's lifetime is that of buf, foo is not borrowed
    //x and foo.buf_ref.buf alias the same memory!
    //but the latter is mutable    
    println!("{}", x[0]); //prints 1
    foo.buf_ref.buf[0] = 4;
    println!("{}", x[0]); //prints what?
}

关于rust - 为什么从 `&' a [u8 ]` to ` &'a mut [u8]` 更改字段会导致生命周期错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57844631/

相关文章:

rust - 为什么actix_rt可以直接在代码中使用,即使它没有声明?

multithreading - 将闭包(返回具有特征的结构)发送到线程会导致大小错误

rust - 使用rust 中未发现的错误

rust - Rust 中的局部函数

rust - 如何修复 : value may contain references; add `' static` bound to `T`

rust - 为什么我不能使用返回编译时常量的函数作为常量?

Rust 中的 TensorFlow, Unresolved 导入

string - 一旦其所有者超出范围,谁是串联字符串的所有者?

windows - 无法在 Windows 上使用 Rust 和 GTK 运行 pkg-config

rust - 有没有办法将基准测试结果保存为 JSON?