在trait上链接函数



我正试图在一个特征上进行可链转换,我遇到了一些问题。

我有一系列变换函数,它们的形式是

fn transform<T: MyTrait>(in: T) -> impl MyTrait

我想要一个函数chain它允许我做

let mut val: Box<MyTrait> = ...;
val = chain(val, transform1);
val = chain(val, transform2);
...
我写了这个函数
fn chain<T, U, F>(val: Box<T>, f: F) -> Box<MyTrait>
  where T: MyTrait,
        U: MyTrait,
        F: FnOnce(T) -> U {
  Box::new(f(*val))
}

但是当我编译时,借用检查器告诉我类型参数U存在的时间不够长。我很确定我的特质界限是我想要的,我用生命周期说明符尝试了各种各样的东西,所以我卡住了:(

注:是否有可能使chain的功能通用于MyTrait ?我认为这是不可能的,但我们永远不知道……

编辑:

我在他的回答中添加了@chris-emerson建议的修复,正如我在评论中所说的,我发现了另一个似乎无法解决的问题。

这里是代码的要点,以免混淆这篇文章。

简而言之,问题是:链函数需要解引用Box<T>对象,并将T传递给变换函数,因此T必须是Sized。但是这个函数的全部意义在于允许使用任意的(在编译时未知的)MyTrait实现。例如:

let mut val: Box<MyTrait> = ...;
//here we can know the type inside the Box
if ... {
  val = chain(val, transform);
}
//but here we don't know anymore
//(its either the original type,
//or the type returned by transform)

所以这个设计不能工作,除非变换函数可以接受&T或&mut(这是不能的,因为我需要消耗输入来产生输出)。

完整的编译器消息是:

error[E0310]: the parameter type `U` may not live long enough
--> <anon>:7:3
  |
7 |   Box::new(f(*val))
  |   ^^^^^^^^^^^^^^^^^
  |
  = help: consider adding an explicit lifetime bound `U: 'static`...
  note:...so that the type `U` will meet its required lifetime bounds
--> <anon>:7:3
  |
7 |   Box::new(f(*val))
  |   ^^^^^^^^^^^^^^^^^
error: aborting due to previous error

编译器说它需要U来维持'static的生存期;这实际上意味着它内部的任何引用都需要在该生命周期内有效,因为Box可以永远存在(只要编译器在这里知道)。

所以修复很简单:将'static添加到U的边界:

fn chain<T, U, F>(val: Box<T>, f: F) -> Box<MyTrait>
  where T: MyTrait,
        U: MyTrait + 'static,
        F: FnOnce(T) -> U,
{
    Box::new(f(*val))
}

添加一个额外的边界U: 'static也是等价的。

相关内容

  • 没有找到相关文章

最新更新