我试图自学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<'_>
。
答案 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<'_>
这是编译器可能改进的东西,但匿名生命期并不容易向用户表达。