声明一个带有生命周期参数的特质对象向量

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<Box<Widget<Ctxt<'c>>>> }?所有的生命周期都必须在静态时已知,并且这将统一它们。 - Shepmaster
在调用f并传入上下文之前,生命周期是未知的。目前(没有使用WV),我只存储一个没有生命周期参数的W1,当调用w1.f()时,特质实际上是为那一刻的Ctxt<'c>专门化的。下次调用w1.f()可能是在Widget<Ctxt<'d>>上;但是w1是相同的。创建不会发生在方法调用的同一作用域中。 - Chris Emerson
1个回答

3

经过一夜的思考,我想我有一个答案。我可以通过新的trait CtxtWidget 间接推迟选择 Ctxt 的生命周期,并为新的trait实现 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>>

我仍然对任何其他解决方案感兴趣(包括有更好的方法进行侵入式更改)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接