2016-09-09 2 views
4

У меня есть Widget черта параметрического от типа контекста:Декларирования вектора признака объектов с пожизненным параметром

trait Widget<C> { 
    fn f<'a>(&self, ctx: &'a mut C); 
} 

Некоторых виджеты, чьи контекст типов одинаковы, но содержат ссылки так параметризируются:

struct Ctxt<'c> { 
    data: &'c u32, 
} 

struct W1 {} 
struct W2 {} 

impl<'c> Widget<Ctxt<'c>> for W1 { // and W2 
    fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) { 
     unimplemented!() 
    } 
} 

у меня есть мульти-виджет, который хочет сохранить некоторые из них:

struct WV { 
    widgets: Vec<Box<Widget<Ctxt<????>>>>, 
} 

impl<'c> Widget<Ctxt<'c>> for WV { 
    fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) { 
     for w in &self.widgets { 
      w.f(ctx); 
     } 
    } 
} 

Похоже, мне нужен Vec<Box<Widget<for<'c> Ctxt<'c>>>>; но вы не можете этого сделать! С другой стороны, только с указанием срока службы в определении f:

impl Widget<Ctxt> for W { 
    fn f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) { 
     unimplemented!() 
    } 
} 

Это не работает, либо (отсутствующий параметр пожизненную Ctxt).

Целью контекста является передача изменчивой ссылки на нечто долговечное, которое необходимо только в течение f; ссылка &mut не может быть сохранена в W1 и т. д. На самом деле я не хочу указывать время жизни для Ctxt.

Как я могу хранить несколько исполнителей этого признака, которые позволяют передавать в контексте, содержащем ссылки?

+2

Я уверен, что чего-то не хватает, но почему бы не использовать 'struct WV <'c> {widgets: Vec >>>}'? Все жизни должны быть известны статически, и это объединит их всех. – Shepmaster

+0

Время жизни неизвестно до фактического вызова 'f', когда у вас есть контекст для перехода. В настоящее время (без' WV') я просто храню 'W1', у которого нет параметров времени жизни, и при вызове' w1.f () 'этот признак эффективно специализирован для' Ctxt <'c> 'в этот момент. В следующий раз вызывается 'w1.f()' оно может быть на 'Widget >'; но 'w1' - то же самое. Создание не происходит в той же области, что и вызов метода. –

ответ

3

После ночного сна, я думаю, у меня есть ответ. Я могу отложить выбор Ctxt жизни путем indirecting через новый признак CtxtWidget и impl<'c> Widget<Ctxt<'c>> для нового признака:

trait Widget<C> { 
    fn f<'a>(&self, ctx: &'a mut C); 
} 

struct W1 {} 
struct W2 {} 
struct Ctxt<'c> { 
    data: &'c u32, 
} 

trait CtxtWidget { 
    fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>); 
} 

impl CtxtWidget for W1 { 
    fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) { 
     unimplemented!() 
    } 
} 
impl CtxtWidget for W2 { 
    fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) { 
     unimplemented!() 
    } 
} 

impl<'c> Widget<Ctxt<'c>> for Box<CtxtWidget> { 
    fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) { 
     self.ctxt_f(ctx); 
    } 
} 

struct WV { 
    pub widgets: Vec<Box<CtxtWidget>>, 
} 

fn main() { 
    let mut wv = WV{widgets: Vec::new()}; 
    wv.widgets.push(Box::new(W1{})); 
    wv.widgets.push(Box::new(W2{})); 
    let u = 65u32; 
    let mut ctxt = Ctxt{data: &u}; 
    for widget in &wv.widgets { 
     widget.f(&mut ctxt); 
    } 
} 

(playground)

В действительности CtxtWidget примерно эквивалентно for<'c> Widget<Ctxt<'c>>.

Меня все равно интересуют любые другие решения (в том числе навязчивые изменения, если есть лучший способ сделать это).