由于现在定义了CallOnceSafe,call_once_safe的调用者可以选择R,而实现者必须保证无论选择什么R,smoltcp::Result<R>将被返回,但是 Option<F> 的任何实现,其中 F: FnOnce(&mut [u8]) -> smoltcp::Result<R> 仅适用于 F 可以返回的特定 R。
唯一合理的解决方案是更改CallOnceSafe 的定义方式。有两种方法可以做到这一点:
- 使
R 成为泛型类型参数。这将允许您选择要为哪个R 实施CallOnceSafe<R>。
trait CallOnceSafe<R> {
fn call_once_safe(&mut self, x: &mut [u8]) -> smoltcp::Result<R>;
}
impl<R, F: FnOnce(&mut [u8]) -> smoltcp::Result<R>> CallOnceSafe<R> for Option<F> {
fn call_once_safe(&mut self, x: &mut [u8]) -> smoltcp::Result<R> {
// panics if called more than once - but A::consume() calls it
// only once
let func = self.take().unwrap();
func(x)
}
}
- 将
R 设为关联类型。这是可行的,因为实现者选择了关联的类型。请注意,我选择将其命名为Ret,因为使用R 会导致type R = R;,我认为这有点令人困惑(但仍然是完全有效的代码)。
trait CallOnceSafe {
type Ret;
fn call_once_safe(&mut self, x: &mut [u8]) -> smoltcp::Result<Self::Ret>;
}
impl<R, F: FnOnce(&mut [u8]) -> smoltcp::Result<R>> CallOnceSafe for Option<F> {
type Ret = R;
fn call_once_safe(&mut self, x: &mut [u8]) -> smoltcp::Result<R> {
// panics if called more than once - but A::consume() calls it
// only once
let func = self.take().unwrap();
func(x)
}
}
两种解决方案的区别在于,泛型类型参数将允许同一类型多次实现 trait,每次使用不同的R,而关联类型只允许一个 impl 用于每种类型。如果您只打算为 Option<F> 实现它并使用它来减少代码重复,这应该无关紧要。