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

时间:2017-10-24 00:45:39

标签: rust borrow-checker

我试图自学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<'_>

1 个答案:

答案 0 :(得分:3)

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

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

没错,生命周期参数丢失了。编译器不会推断'a中的生命周期参数StdStreams<'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更长,但该方法不会强加该约束。因此,我们可以将lifetime参数绑定到与引用相同的生命周期:

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

或者为生命周期参数添加约束。

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

我也发现这种不必要的讽刺:预期&mut StdStreams<'_>,找到&mut StdStreams<'_>

这是编译器可能改进的东西,但匿名生命期并不容易向用户表达。