不满足 Rust 特征边界。中间分配是必要的,或者删除 Trait 实现

Rust trait bounds not satisfied. Either intermediate assignment is necessary, or removal of a Trait implementation

我希望能够为不同的函数签名实现一个特征,但编译器给我奇怪的错误。我试图在以下最小示例中减少问题:

trait MyTrait<P> {
    fn trait_method(&self, p: P);
}

impl MyTrait<fn(u32)> for MyStruct {
    fn trait_method(&self, p: fn(u32)) {
        todo!()
    }
}

impl MyTrait<fn(u64)> for MyStruct {
    fn trait_method(&self, p: fn(u64)) {
        todo!()
    }
}

struct MyStruct;

fn test() {
    let my_struct = MyStruct;

    // Gives error:
    // the trait bound `MyStruct: MyTrait<fn(u32) {test_fun}>` is not satisfied
    //      the following implementations were found:
    //  <MyStruct as MyTrait<fn(u32)>>
    //  <MyStruct as MyTrait<fn(u64)>>
    my_struct.trait_method(test_fun);

    // Is ok
    let fun: fn(u32) = test_fun;
    my_struct.trait_method(fun);

    // Gives error
    // the trait bound `MyStruct: MyTrait<[closure@src/main.rs:176:28: 176:39]>` is not satisfied
    //      the following implementations were found:
    //  <MyStruct as MyTrait<fn(u32)>>
    //  <MyStruct as MyTrait<fn(u64)>>
    my_struct.trait_method(|hi: u32|{});

    // Is ok
    let fun: fn(u32) = |hi: u32|{};
    my_struct.trait_method(fun);
}

fn test_fun(hi: u32) {}

如果我删除 impl MyTrait<fn(u64)> 块,那么问题就会消失,我可以使用任何一种方式调用 Trait 函数。只有当我有多个相同特征的实现时,才会出现这些错误。

为什么这个 Rust 代码不正确,我可以用什么方法来解决这个问题?对我来说非常重要的是它可以在没有中间赋值的情况下调用,因为这个特征最终会出现在 public API.

提前致谢

编辑: 以下代码也适用:

my_struct.trait_method(test_fun as fn(u32));

让我们比较一下:

let fun: fn(u32) = test_fun;

还有这个:

let fun = test_fun;

第一个例子中 fun 的类型明确设置为 fn(u32),而在第二个版本中它实际上是 fn(u32) {test_fun}。那是两种不同的类型。第一个是 函数指针 。第二个是功能项。当您显式指定 fun 的类型时,发生的事情称为 coercion.

好的,我设法解决了这个问题:

pub trait VarFunc<A, P, R, T> {}

impl<F, A: Actor, P, R> VarFunc<A, P, R, WithState> for F where
    F: Fn(&mut A, &mut State<A>, P) -> Flow<A, R>
{
}

impl<F, A: Actor, P, R> VarFunc<A, P, R, WithoutState> for F where
    F: Fn(&mut A, P) -> Flow<A, R>
{
}

pub struct WithState;
pub struct WithoutState;

基本上,我创建了一个新特征 VarFunc,它可以同时实现 WithStateWithoutState。然后,在指定 Trait impl 时,我们不使用 F: Fn(X) -> Y,而是使用 F: VarFunc<StateX/StateY>,这实际上可以被编译器视为不同的