有什么方法可以为特征绑定定义别名?

时间:2018-09-11 23:15:11

标签: rust

我有一个包含回调的结构:

struct MyStruct<F>
where
    F: Fn(u32) -> u32,
{
    cb: F,
}

impl<F> MyStruct<F>
where
    F: Fn(u32) -> u32,
{
    fn invoke(&self, val: u32) -> u32 {
        (self.cb)(val)
    }
}

fn callback(val: u32) -> u32 {
    val + 1
}

fn main() {
    let s = MyStruct { cb: callback };
    s.invoke(0);
}

我想避免重复输入Fn(u32) -> u32,特别是当它是一个更复杂的签名,或者我需要存储多个具有相同签名的回调时。有什么方法可以为特征绑定定义别名?我试图通过衍生特征来做到这一点,就像这样:

pub trait CallbackFn: Fn(u32) -> u32 {}

struct MyStruct<F>
where
    F: CallbackFn,
{
    cb: F,
}

impl<F> MyStruct<F>
where
    F: CallbackFn,
{
    fn invoke(&self, val: u32) -> u32 {
        (self.cb)(val)
    }
}

fn callback(val: u32) -> u32 {
    val + 1
}

fn main() {
    let s = MyStruct { cb: callback };
    s.invoke(0);
}

但这无法编译:

error[E0277]: the trait bound `fn(u32) -> u32 {callback}: CallbackFn` is not satisfied
  --> src/main.rs:24:13
   |
24 |     let s = MyStruct { cb: callback };
   |             ^^^^^^^^ the trait `CallbackFn` is not implemented for `fn(u32) -> u32 {callback}`
   |
note: required by `MyStruct`
  --> src/main.rs:3:1
   |
3  | / struct MyStruct<F>
4  | | where
5  | |     F: CallbackFn,
6  | | {
7  | |     cb: F,
8  | | }
   | |_^

error[E0599]: no method named `invoke` found for type `MyStruct<fn(u32) -> u32 {callback}>` in the current scope
  --> src/main.rs:25:7
   |
3  | / struct MyStruct<F>
4  | | where
5  | |     F: CallbackFn,
6  | | {
7  | |     cb: F,
8  | | }
   | |_- method `invoke` not found for this
...
25 |       s.invoke(0);
   |         ^^^^^^
   |
   = note: the method `invoke` exists but the following trait bounds were not satisfied:
           `fn(u32) -> u32 {callback} : CallbackFn`

类型别名不能完全切掉它,因为它不允许传递闭包,而只是一个简单的函数指针-例如:

type F = fn(u32) -> u32;

struct MyStruct {
    cb: F,
}

impl MyStruct {
    fn invoke(&self, val: u32) -> u32 {
        (self.cb)(val)
    }
}

fn main() {
    let s = MyStruct { cb: |x| x + 1 }; // works
    let v = 5u32;
    let t = MyStruct { cb: |x| (x + v) }; // fails
    s.invoke(0);
    t.invoke(1);
}

0 个答案:

没有答案