如何在返回类型上实现泛型的特征函数

时间:2021-03-25 03:36:25

标签: rust

trait CallOnceSafe {
    fn call_once_safe<R>(&mut self, x: &mut [u8]) -> smoltcp::Result<R>;
}

impl<R, F: FnOnce(&mut [u8]) -> smoltcp::Result<R>> CallOnceSafe for Option<F> {
    fn call_once_safe<R>(&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)
    }
}

在这种情况下,我不能使用 fn call_once_safe<R>,因为 R 已经被用作实现 trail 的类型参数。

如何使用泛型类型 R 实现这个特征函数?

1 个答案:

答案 0 :(得分:2)

由于现在定义了CallOnceSafecall_once_safe的调用者可以选择R,而实现者必须保证无论{{1} } 是选择,将返回 R,但是 smoltcp::Result<R> 的任何实现,其中 Option<F> 仅适用于 F: FnOnce(&mut [u8]) -> smoltcp::Result<R> 可以返回的特定 R。< /p>

唯一合理的解决方案是更改 F 的定义方式。有两种方法可以做到这一点:

  • 使 CallOnceSafe 成为泛型类型参数。这将允许您选择要实施 RR
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,每次使用不同的 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) } } ,而关联类型只允许一个 {{ 1}} 为每种类型。如果您只打算为 R 实施它并使用它来减少代码重复,这应该无关紧要。