在特征上链接函数
Chaining functions on a 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 的寿命不够长。我很确定我的特征界限是我想要的,并且我已经尝试了各种使用生命周期说明符的东西,所以我被卡住了:(
P.S。 : 是否可以使 chain
函数在 MyTrait
上通用?我不认为这是可能的,但我们永远不知道...
编辑:
我在他的回答中添加了@chris-emerson 提出的修复,正如我在其评论中所说,我发现了另一个似乎无法解决的问题。
Here 是代码的要点,不要让 post.
混乱
简而言之,问题是:链函数需要取消引用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
也是等效的。
我正在尝试对特征进行链式转换,但遇到了一些问题。
我有一堆形式的转换函数:
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 提出的修复,正如我在其评论中所说,我发现了另一个似乎无法解决的问题。
Here 是代码的要点,不要让 post.
混乱简而言之,问题是:链函数需要取消引用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
也是等效的。