我正在尝试对一个特征进行可链接的转换,并且遇到了一些问题。

我有一堆形式的转换函数:

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的生存期不够长。我很确定我的特质界限就是我想要的,并且我已经用生命周期说明符尝试了各种事情,所以我被困住了:(

P.S. :是否可以使chain函数在MyTrait上通用?我认为这是不可能的,但我们永远不知道...

编辑:

我已经在@ chris-emerson的答案中添加了@ chris-emerson提出的修复程序,正如我在评论中所说,我发现了另一个似乎无法解决的问题。

Here是代码的要点,不要使这篇文章困惑。

简而言之,问题在于:链函数需要取消引用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 T(因为我需要消耗输入才能产生输出,所以它不能这样做),否则该设计将无法正常工作。

最佳答案

完整的编译器消息为:

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也将是等效的。

关于generics - 特质上的链接功能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40169498/

10-12 14:56