我正在尝试对一个特征进行可链接的转换,并且遇到了一些问题。
我有一堆形式的转换函数:
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/