如何在Rust中的迭代器适配器内部延长临时变量的生存期? [英] How can I extend the lifetime of a temporary variable inside of an iterator adaptor in Rust?

查看:155
本文介绍了如何在Rust中的迭代器适配器内部延长临时变量的生存期?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个方法make_iter(),该方法在Rust中创建具有多个适配器的Iterator,可以将其简化为以下MCVE:

I have a method make_iter() which creates an Iterator with multiple adapters in Rust, which can be simplified as the following 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

这是可以理解的,因为second对象是一个临时对象,并且从同一闭包返回的迭代器尝试借用它,但由于second在闭包的末端被删除而失败. 我的目标是延长该对象的寿命,直到删除引用它的Iterator,但我不知道如何.

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. My objective would be to extend the lifetime of this object until the Iterator referencing it is dropped, but I don't know how.

请注意,不能更改结构实现. Rust版本为1.34.2,2018版

Note that the structure implementations cannot be changed. Rust version is 1.34.2, edition 2018

推荐答案

延长该对象的寿命

extend the lifetime of this object

期间,您无法执行此操作.根本不是事情的运作方式.

You cannot do this, period. It's simply not how things work.

另请参阅:

  • Extend lifetime of variable
  • Extending borrowed lifetime for String slice
  • Is there any way to return a reference to a variable created in a function?

这是一个简单的复制品:

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()
    }
}

由于存在无法更改Inner的限制,因此最简单的解决方案是更加积极主动地collect:

Since you have the restriction of being unable to change Inner, the easiest solution is to be more eager and proactively collect:

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

我知道避免发生这种情况的唯一可能性就是使用类似 rental owning_ref .

The only possibility I know of to avoid that would be to use a crate like rental or owning_ref.

另请参阅:

  • Is there an owned version of String::chars?
  • How can I store a Chars iterator in the same struct as the String it is iterating on?

如果您可以更改Inner,则应使用较复杂的迭代器.然后,该值不需要超出闭包,因为迭代器已拥有所有权.

If you had the possibility of changing Inner, you should make a consuming iterator variant. 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()
    }
}

这篇关于如何在Rust中的迭代器适配器内部延长临时变量的生存期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆