Как я могу продлить время жизни временной переменной внутри адаптера итератора в Rust? - PullRequest
0 голосов
/ 20 июня 2019

У меня есть метод 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())
    }
}

Попытка скомпилировать этот пример приводит к пожизненной ошибке:

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 отбрасывается в конце замыкания.Моя цель - продлить срок жизни этого объекта до тех пор, пока итератор, ссылающийся на него, не будет удален, но я не знаю, как.

Обратите внимание, что реализации структуры не могут быть изменены.Версия Rust 1.34.2, выпуск 2018

1 Ответ

2 голосов
/ 21 июня 2019

продлить срок жизни этого объекта

Вы не можете этого сделать, точка.Это просто не то, как все работает.

См. Также:

Вот более простое воспроизведение:

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:

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

Единственная известная мне возможность избежать этогобудет использовать ящик типа аренда или owning_ref .

См. также:

Если выИмея возможность изменить Inner, вы должны сделать потребляющий вариант итератора.Тогда значение не должно жить после замыкания, потому что итератор вступил во владение.

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()
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...