指定参数的生命周期持续函数调用
Specify that lifetime of argument lasts for function call
我有一个带有引用迭代器的函数的特征:
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction<'a, I>
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I);
}
struct DogListActionExample {}
impl<'a, I> DogListAction<'a, I> for DogListActionExample
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let mut action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction<_>>> = vec![Box::new(action_example)];
loop {
let dog_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(dog_clone.iter());
}
}
}
它不引用任何元素,所以它不需要比函数调用持续更多的时间。
由于我对生生世世的理解有限,我还不知道该如何表达。调用此函数导致编译错误:
error[E0597]: `dog_clone` does not live long enough
--> src/main.rs:33:41
|
33 | dog_list_action.on_dog_list(dog_clone.iter());
| ^^^^^^^^^ borrowed value does not live long enough
34 | }
35 | }
| - `dog_clone` dropped here while still borrowed
36 | }
| - borrowed value needs to live until here
我猜借用检查器认为函数结束后可能会引用dog_clone
中的数据,但事实并非如此。
这里的问题是,代码可能会在长期 dog_list_actions
中保存对 dog_clone
元素的短期引用。我们需要告诉编译器我们不会保存迭代器产生的引用。可以这样做:
trait DogListAction {
fn on_dog_list<'a, I>(&'a mut self, dog_list: I)
where
I: Iterator<Item = &'a Dog>;
}
现在 Item
可以在 on_dog_list
通话期间存活。在原始代码中,它们 必须 存活更长时间。
但是这段代码产生了另一个问题:我们不能再装箱特征 DogListAction
因为它包含通用函数。这里通常的做法是使用特征对象:
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
注意 Box<dyn Iterator<Item = &'a Dog> + 'a>
中的第二个 'a
。 Rust 默认添加绑定到盒装特征对象的 'static
特征,我们不希望此处 'static
。
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
struct DogListActionExample {}
impl DogListAction for DogListActionExample {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction>> = vec![Box::new(action_example)];
{
let dogs_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(Box::new(dogs_clone.iter()));
}
}
}
我有一个带有引用迭代器的函数的特征:
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction<'a, I>
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I);
}
struct DogListActionExample {}
impl<'a, I> DogListAction<'a, I> for DogListActionExample
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let mut action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction<_>>> = vec![Box::new(action_example)];
loop {
let dog_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(dog_clone.iter());
}
}
}
它不引用任何元素,所以它不需要比函数调用持续更多的时间。
由于我对生生世世的理解有限,我还不知道该如何表达。调用此函数导致编译错误:
error[E0597]: `dog_clone` does not live long enough
--> src/main.rs:33:41
|
33 | dog_list_action.on_dog_list(dog_clone.iter());
| ^^^^^^^^^ borrowed value does not live long enough
34 | }
35 | }
| - `dog_clone` dropped here while still borrowed
36 | }
| - borrowed value needs to live until here
我猜借用检查器认为函数结束后可能会引用dog_clone
中的数据,但事实并非如此。
这里的问题是,代码可能会在长期 dog_list_actions
中保存对 dog_clone
元素的短期引用。我们需要告诉编译器我们不会保存迭代器产生的引用。可以这样做:
trait DogListAction {
fn on_dog_list<'a, I>(&'a mut self, dog_list: I)
where
I: Iterator<Item = &'a Dog>;
}
现在 Item
可以在 on_dog_list
通话期间存活。在原始代码中,它们 必须 存活更长时间。
但是这段代码产生了另一个问题:我们不能再装箱特征 DogListAction
因为它包含通用函数。这里通常的做法是使用特征对象:
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
注意 Box<dyn Iterator<Item = &'a Dog> + 'a>
中的第二个 'a
。 Rust 默认添加绑定到盒装特征对象的 'static
特征,我们不希望此处 'static
。
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
struct DogListActionExample {}
impl DogListAction for DogListActionExample {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction>> = vec![Box::new(action_example)];
{
let dogs_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(Box::new(dogs_clone.iter()));
}
}
}