Время жизни и связанные типы данных

#rust

#Ржавчина

Вопрос:

У меня есть процесс, который занимает несколько шагов. Шаги определены ниже как структуры единиц и имеют связанные данные через Step признак. Каждый шаг содержит данные, которые могут быть преобразованы каждым исполнителем. И у него есть связанный NextStep , который является следующим шагом. У данных Note Step2 есть время жизни, и для того, чтобы это работало Step2 , в struct есть некоторые пожизненные махинации.

 use std::marker::PhantomData;

trait Step {
    type Data;
    type NextStep: Step;
}

struct LifetimeData<'a>(amp;'a mut i32);

// The definitions of Steps are not important, these are used as marker types
struct Step1;
// Here Step2 needs a lifetime because of its associated data  
struct Step2<'a>(PhantomData<amp;'a ()>);
struct Step3;

impl Step for Step1 {
    type Data = ();
    // This shouldn't be 'static, not sure what and how I should qualify the lifetime of Step2 thought...?
    type NextStep = Step2<'static>;
}

impl<'a> Step for Step2<'a> {
    type Data = LifetimeData<'a>;
    type NextStep = Step3;
}

impl Step for Step3 {
    type Data = ();
    type NextStep = ();
}

// Needed as a final step ...
impl Step for () {
    type Data = ();
    type NextStep = ();
}
 

существует проблема с объявлением, о Step1::NextStep которой будет рассказано позже

Из этих шагов есть бегуны. Они работают с доступными данными и могут преобразовывать, считывать и обрабатывать их. После каждого шага и бегунов для этого шага можно взять себя и создавать бегунов для следующего шага. Обратите внимание, что бегун должен пережить данные S::Data (например amp;mut self , время жизни> data: amp;mut S::Data время жизни), чтобы они не могли взять ссылку из данных шага и передать ее следующему шагу, поскольку она может быть признана недействительной после шага (я не уверен, есть ли у меня время жизни прямо здесь, чтобы это было запрещено).

 trait StepRunner<S: Step> {
    fn do_thing(amp;mut self, data: amp;mut S::Data);
    fn into_next_step(self: Box<Self>) -> Vec<Box<dyn StepRunner<S::NextStep>>>;
}
 

Существует функция для создания пошагового бегуна. Затем существует run функция, которая принимает генераторы для каждого шага, создает бегуны на каждом шаге и выполняет обработку данных. Генерация бегунов работает, и бегуны первого шага работают нормально.

 trait StepRunnerGenerator<S: Step> {
    fn generate(amp;mut self) -> Vec<Box<dyn StepRunner<S>>>;
}

fn run(
    first_step_runners_generators: Vec<Box<dyn StepRunnerGenerator<Step1>>>,
    second_step_runners_generators: Vec<Box<dyn for<'a> StepRunnerGenerator<Step2<'a>>>>,
    third_step_runners_generators: Vec<Box<dyn StepRunnerGenerator<Step3>>>,
) {
    let mut first_step_runners = first_step_runners_generators
        .into_iter()
        .flat_map(|mut gen| gen.generate())
        .collect::<Vec<_>>();

    first_step_runners
        .iter_mut()
        .for_each(|runner| runner.do_thing(amp;mut ()));

    let mut value = 4_i32;

    let mut third_pass_runners = {
        let mut second_step_runners_generators = second_step_runners_generators
            .into_iter()
            .flat_map(|mut gen| gen.generate())
            .chain(first_step_runners.into_iter().flat_map(|runner| runner.into_next_step()))
            .collect::<Vec<_>>();
        // The compiler doesn't like this because the `.chain(first_step_runners.into_iter().flat_map(|runner| runner.into_next_step()))`
        // statement above returns a StepRunner<Step2<'static>>. And that 'static requires data to be 
        // accessible for the rest of the program 
        let mut data = LifetimeData(amp;mut value);

        second_step_runners_generators
            .iter_mut()
            .for_each(|runner| runner.do_thing(amp;mut data));

        third_step_runners_generators
            .into_iter()
            .flat_map(|mut gen| gen.generate())
            .chain(second_step_runners_generators.into_iter().flat_map(|runner| runner.into_next_step()))
            .collect::<Vec<_>>()
    };

    value  = 1;

    third_pass_runners
        .iter_mut()
        .for_each(|runner| runner.do_thing(amp;mut ()));
}
 

Проблема заключается в преобразовании бегунов шага 1 в шаг 2. Смотрите Step Реализацию для Step1 current написано с 'static временем жизни:

 impl Step for Step1 {
    ...
    type NextStep = Step2<'static>;
}
 

Это означает, что у пошаговых бегунов из second_step_runners_generators.into_iter().flat_map(|runner| runner.into_next_step()) есть время жизни их данных as LifetimeData<'static> .

И это вызывает let mut data = LifetimeData(amp;mut value); необходимость жить 'static и означает, что value = 1; это невозможно сделать, потому что в то время оно изменчиво заимствуется: (

Как я могу сделать так, чтобы время жизни <Step1 as Step>::NextStep не было 'static таким run , чтобы функция работала …? Требуется ли в этом случае generic_associated_types ? Есть ли лучшее решение, которое работает сегодня на стабильной …?