闭包参数的生命周期注解
Lifetime annotation for closure argument
我想编译以下代码:
struct Provider {}
impl Provider {
fn get_string<'a>(&'a self) -> &'a str { "this is a string" }
}
fn main() {
let provider = Provider{};
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let fun = |s: &str| {
vec.push(s);
};
fun(provider.get_string());
}
这是我得到的编译错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:9:22
|
9 | let mut vec: Vec<&str> = Vec::new();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 11:24...
--> src/main.rs:11:25
|
11| let fun = |s: &str| {
| ^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:18
|
12| vec.push(s);
| ^
note: but, the lifetime must be valid for the block suffix following statement 2 at 13:6...
--> src/main.rs:13:7
|
13| };
| ^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:11:9
|
11| let fun = |s: &str| {
| ^^^
这是一个编译版本:
use std::marker::PhantomData;
struct Provider<'a> {
_dummy: PhantomData<&'a ()>,
}
impl<'a> Provider<'a> {
fn get_string(&self) -> &'a str {
"this is a string"
}
}
fn f<'b>() {
let provider = Provider { _dummy: PhantomData };
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let mut fun = |s: &'b str| { vec.push(s); };
fun(provider.get_string());
}
fn main() {
f()
}
我做了以下更改:
- 为
Provider
添加一个生命周期(我添加了一个 PhantomData
,但我猜你的提供商已经拥有它将提供的一些数据)。
- 更新
get_string
方法以表明它 returns 与提供者的生命周期有关,而不是输入生命周期(即基于 Provider
的生命周期参数)。
- 向函数添加一个新的生命周期参数
'b
(我将其重命名为f()
,因为main()
不能有),我用它来命名生命周期闭包参数。
最后一个有点令人困惑,因为显然只是在生命周期中添加一个名称(没有明显添加任何约束)就可以了。
我认为(但我希望为此提供一些文档)这是因为生命周期省略。闭包实际上是一个隐藏的 struct
和 fn call(&self, s: &str)
(在本例中)方法。根据 lifetime elision rules,s
参数获得与 &self
相同的生命周期,即闭包本身。在这种情况下,闭包是在 vec
之后声明的,因此生命周期太短了。显式生命周期意味着它与闭包自身的生命周期解耦。
如果删除所有生命周期注释并让编译器推理完成它的工作,您的代码就可以正常工作:
struct Provider;
impl Provider {
fn get_string(&self) -> &str { "this is a string" }
}
fn main() {
let provider = Provider;
let mut vec = Vec::new();
let mut fun = |s| {
vec.push(s);
};
fun(provider.get_string());
}
简而言之,无法显式引用局部变量的生命周期,只能引用函数参数。不过,编译器知道该怎么做。
如果你真的需要它,你可以创建一个函数来允许注释生命周期:
fn thing<'a>(provider: &'a Provider) -> Vec<&'a str> {
let mut vec: Vec<&'a str> = Vec::new();
{
let mut fun = |s: &'a str| vec.push(s);
fun(provider.get_string());
} // End mutable borrow of `vec`
vec
}
fn main() {
let provider = Provider;
thing(&provider);
}
why did the original annotations stop things from working?
具体是这个位:
let fun = |s: &str| {
vec.push(s);
};
这在闭包上声明了一个新的生命周期。使用 made-up 语法 (你 ),它等同于:
let fun = <'a> |s: &'a str| {
vec.push(s);
};
这就是编译器出现错误的原因:
the lifetime cannot outlive the anonymous lifetime #1 defined on [the closure's block]
生成的生命周期与 Provider
的生命周期之间没有联系。将其保留在外允许编译器插入所需但不可命名的生命周期。
我想编译以下代码:
struct Provider {}
impl Provider {
fn get_string<'a>(&'a self) -> &'a str { "this is a string" }
}
fn main() {
let provider = Provider{};
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let fun = |s: &str| {
vec.push(s);
};
fun(provider.get_string());
}
这是我得到的编译错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:9:22
|
9 | let mut vec: Vec<&str> = Vec::new();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 11:24...
--> src/main.rs:11:25
|
11| let fun = |s: &str| {
| ^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:18
|
12| vec.push(s);
| ^
note: but, the lifetime must be valid for the block suffix following statement 2 at 13:6...
--> src/main.rs:13:7
|
13| };
| ^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:11:9
|
11| let fun = |s: &str| {
| ^^^
这是一个编译版本:
use std::marker::PhantomData;
struct Provider<'a> {
_dummy: PhantomData<&'a ()>,
}
impl<'a> Provider<'a> {
fn get_string(&self) -> &'a str {
"this is a string"
}
}
fn f<'b>() {
let provider = Provider { _dummy: PhantomData };
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let mut fun = |s: &'b str| { vec.push(s); };
fun(provider.get_string());
}
fn main() {
f()
}
我做了以下更改:
- 为
Provider
添加一个生命周期(我添加了一个PhantomData
,但我猜你的提供商已经拥有它将提供的一些数据)。 - 更新
get_string
方法以表明它 returns 与提供者的生命周期有关,而不是输入生命周期(即基于Provider
的生命周期参数)。 - 向函数添加一个新的生命周期参数
'b
(我将其重命名为f()
,因为main()
不能有),我用它来命名生命周期闭包参数。
最后一个有点令人困惑,因为显然只是在生命周期中添加一个名称(没有明显添加任何约束)就可以了。
我认为(但我希望为此提供一些文档)这是因为生命周期省略。闭包实际上是一个隐藏的 struct
和 fn call(&self, s: &str)
(在本例中)方法。根据 lifetime elision rules,s
参数获得与 &self
相同的生命周期,即闭包本身。在这种情况下,闭包是在 vec
之后声明的,因此生命周期太短了。显式生命周期意味着它与闭包自身的生命周期解耦。
如果删除所有生命周期注释并让编译器推理完成它的工作,您的代码就可以正常工作:
struct Provider;
impl Provider {
fn get_string(&self) -> &str { "this is a string" }
}
fn main() {
let provider = Provider;
let mut vec = Vec::new();
let mut fun = |s| {
vec.push(s);
};
fun(provider.get_string());
}
简而言之,无法显式引用局部变量的生命周期,只能引用函数参数。不过,编译器知道该怎么做。
如果你真的需要它,你可以创建一个函数来允许注释生命周期:
fn thing<'a>(provider: &'a Provider) -> Vec<&'a str> {
let mut vec: Vec<&'a str> = Vec::new();
{
let mut fun = |s: &'a str| vec.push(s);
fun(provider.get_string());
} // End mutable borrow of `vec`
vec
}
fn main() {
let provider = Provider;
thing(&provider);
}
why did the original annotations stop things from working?
具体是这个位:
let fun = |s: &str| {
vec.push(s);
};
这在闭包上声明了一个新的生命周期。使用 made-up 语法 (你
let fun = <'a> |s: &'a str| {
vec.push(s);
};
这就是编译器出现错误的原因:
the lifetime cannot outlive the anonymous lifetime #1 defined on [the closure's block]
生成的生命周期与 Provider
的生命周期之间没有联系。将其保留在外允许编译器插入所需但不可命名的生命周期。