简体   繁体   English

如何在Rust中延长迭代器适配器内部临时变量的寿命?

[英]How can I extend the lifetime of a temporary variable inside of an iterator adaptor in Rust?

I have a method make_iter() which creates an Iterator with multiple adapters in Rust, which can be simplified as the following MCVE: 我有一个方法make_iter() ,它在Rust中用多个适配器创建一个迭代器,可以简化为以下MCVE:

fn make_iter(first: &First) -> Box<dyn Iterator<Item = String> + '_> {
    Box::new(first.make_objects().flat_map(|second| {
        second
            .iter()
            .filter(|third| third.as_str() != "t2")
            .flat_map(|third| vec![format!("{}.A", third), format!("{}.B", third)].into_iter())
            .chain(
                vec![
                    format!("{}.A", second.name()),
                    format!("{}.B", second.name()),
                ]
                .into_iter(),
            )
    }))
}

pub fn main() {
    let first = First {};
    for i in make_iter(&first) {
        println!("{}", i);
    }
}

struct First {}

impl First {
    fn make_objects(&self) -> Box<dyn Iterator<Item = Second> + '_> {
        Box::new(
            vec![
                Second::new("s1".to_string()),
                Second::new("s2".to_string()),
                Second::new("s3".to_string()),
            ]
            .into_iter(),
        )
    }
}

struct Second {
    name: String,
    objects: Vec<String>,
}

impl Second {
    fn new(name: String) -> Second {
        Second {
            name,
            objects: vec!["t1".to_string(), "t2".to_string(), "t3".to_string()],
        }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn iter(&self) -> Box<dyn Iterator<Item = &String> + '_> {
        Box::new(self.objects.iter())
    }
}

Trying to compile this example yields a lifetime error: 尝试编译此示例会产生生命周期错误:

error[E0597]: `second` does not live long enough
  --> src/main.rs:3:9
   |
3  |         second
   |         ^^^^^^ borrowed value does not live long enough
...
14 |     }))
   |     - `second` dropped here while still borrowed

This is understandable, as the second object is a temporary, and the iterator returned from the same closure attempts to borrow it, failing as second is dropped at the closure's end. 这是可以理解的,因为second对象是一个临时对象,并且从同一个闭包返回的迭代器尝试借用它,但由于second对象在闭包的末端被丢弃而失败。 My objective would be to extend the lifetime of this object until the Iterator referencing it is dropped, but I don't know how. 我的目标是延长该对象的寿命,直到删除引用它的Iterator,但我不知道如何做。

Note that the structure implementations cannot be changed. 注意,结构实现不能更改。 Rust version is 1.34.2, edition 2018 Rust版本是1.34.2,2018版

extend the lifetime of this object 延长此对象的寿命

You cannot do this, period. 期间,您无法执行此操作。 It's simply not how things work. 根本不是事情如何运作。

See also: 也可以看看:

Here's a simpler reproduction: 这是一个简单的复制:

use std::iter;

fn example(outer: impl Iterator<Item = Inner>) {
    outer.flat_map(|i| i.iter().map(|v| v.clone()));
}

struct Inner;

impl Inner {
    fn iter(&self) -> impl Iterator<Item = &()> + '_ {
        iter::empty()
    }
}

Since you have the restriction of being unable to change Inner , the easiest solution is to be more eager and proactively collect : 由于存在无法更改Inner的限制,因此最简单的解决方案是更积极主动地进行collect

fn example(outer: impl Iterator<Item = Inner>) {
    outer.flat_map(|i| i.iter().map(|v| v.clone()).collect::<Vec<_>>());
}

The only possibility I know of to avoid that would be to use a crate like rental or owning_ref . 我知道避免发生这种情况的唯一可能性是使用一个板条箱,例如rentalowning_ref

See also: 也可以看看:

If you had the possibility of changing Inner , you should make a consuming iterator variant. 如果您有可能更改Inner ,则应制作一个消耗量大的迭代器变体。 Then the value does not need to live beyond the closure because the iterator has taken ownership. 然后,该值不需要超出闭包,因为迭代器已拥有所有权。

use std::iter;

fn example(outer: impl Iterator<Item = Inner>) {
    outer.flat_map(|i| i.into_iter().map(|v| v));
}

struct Inner;

impl Inner {
    fn into_iter(self) -> impl Iterator<Item = ()> {
        iter::empty()
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM