#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 ? Есть ли лучшее решение, которое работает сегодня на стабильной …?