Rust 抱怨生命周期要求冲突,没有迭代器或闭包

Rust complains of conflicting lifetime requirements, no iterators or closures

我正在尝试自学 Rust。我熟悉 C++ 和 Scala,但 Rust 对我来说仍然是一种 Perlish 语言。

为了这段代码,我已经和借用检查器争吵了两天。这对我来说似乎很清楚,但我无法让 Rust 同意。

这很简单,我可以得到代码但仍然会产生错误:

use std::io;

fn main() {
    let mut streams: StdStreams = StdStreams {
        stderr: &mut io::stderr(),
    };
    let command = Command {};
    let streams_ref: &mut StdStreams = &mut streams;
    command.go(streams_ref);
}

pub struct StdStreams<'a> {
    stderr: &'a mut io::Write,
}

pub struct Command {}

impl Command {
    pub fn go(&self, streams: &mut ::StdStreams) {
        let mut server = Server { streams };
    }
}

pub struct Server<'a> {
    pub streams: &'a mut StdStreams<'a>,
}

编译器的意见如下:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:20:26
   |
20 |         let mut server = Server { streams };
   |                          ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 19:5...
  --> src/main.rs:19:5
   |
19 | /     pub fn go(&self, streams: &mut ::StdStreams) {
20 | |         let mut server = Server { streams };
21 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:20:35
   |
20 |         let mut server = Server { streams };
   |                                   ^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #3 defined on the method body at 19:5...
  --> src/main.rs:19:5
   |
19 | /     pub fn go(&self, streams: &mut ::StdStreams) {
20 | |         let mut server = Server { streams };
21 | |     }
   | |_____^
note: ...so that expression is assignable (expected &mut StdStreams<'_>, found &mut StdStreams<'_>)
  --> src/main.rs:20:35
   |
20 |         let mut server = Server { streams };
   |                                   ^^^^^^^

我似乎很清楚,我正在存储有问题的引用的项目将超出范围并立即消失,同时它存储的引用也会消失,所以不应该有任何不愉快。

我也觉得这是不必要的讽刺:expected &mut StdStreams<'_>, found &mut StdStreams<'_>

当我们看到编译器如何在 go 方法中显式显示所有生命周期时,问题变得更加清晰:

pub fn go<'a, 'b, 'c>(&'a self, streams: &'b mut StdStreams<'c>) {
    let mut server = Server {streams};
}

没错,缺少一个生命周期参数。编译器不会推断 StdStreams<'a> 中的生命周期参数 'a 将与类型 &mut StdStreams 的引用的生命周期相同(例如,它不会产生 &'a Foo<'a>. 编译器也会在可能的情况下在其错误消息中使用这些命名的生命周期:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:20:26
   |
20 |         let mut server = Server {streams};
   |                          ^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime 'b as defined on the method body at 19:5...
  --> src/main.rs:19:5
   |
19 | /     pub fn go<'a, 'b, 'c>(&'a self, streams: &'b mut StdStreams<'c>) {
20 | |         let mut server = Server {streams};
21 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:20:34
   |
20 |         let mut server = Server {streams};
   |                                  ^^^^^^^
note: but, the lifetime must be valid for the lifetime 'c as defined on the method body at 19:5...
  --> src/main.rs:19:5
   |
19 | /     pub fn go<'a, 'b, 'c>(&'a self, streams: &'b mut StdStreams<'c>) {
20 | |         let mut server = Server {streams};
21 | |     }
   | |_____^
note: ...so that expression is assignable (expected &mut StdStreams<'_>, found &mut StdStreams<'c>)
  --> src/main.rs:20:34
   |
20 |         let mut server = Server {streams};
   |                                  ^^^^^^^ 

冲突现在应该很清楚了:'b 需要超过生命周期 'c,但该方法没有强加该约束。因此,我们可以将生命周期参数绑定到与引用相同的生命周期:

pub fn go<'a>(&self, streams: &'a mut StdStreams<'a>) {
}

或者给lifetime参数加一个约束。

pub fn go<'a: 'b, 'b>(&self, streams: &'a mut StdStreams<'b>) {
}

I also find this needlessly sarcastic: expected &mut StdStreams<'_>, found &mut StdStreams<'_>

编译器可能会改进这一点,但匿名生命周期并不容易向用户表达。