有没有一种方法可以在Rust中接受多个回调方法?

时间:2019-08-21 05:36:33

标签: types rust

我正在尝试为我的库实现语法糖,以便如果没有有趣的状态管理正在进行时,某人可以编写.render(|image| { … })而不是.render(|(), image| { … })。我认为我可以通过为所有FnMut(&State, &Image)实现一个特征并为FnMut(&Image)实现一个单元实现来做到这一点。不幸的是,当我尝试实现这一点时,我会遇到“冲突的实现”错误,因为没有理由不能同时实现这两个FnMut特性。

我当前的尝试如下:

trait RenderCallback<State> {
    fn render(&mut self, state: &mut State, image: &mut Image);
}

impl<F, State> RenderCallback<State> for F
where
    F: FnMut(&mut State, &mut Image),
{
    fn render(&mut self, state: &mut State, image: &mut Image) {
        self(state, image)
    }
}

impl<F> RenderCallback<()> for F
where
    F: FnMut(&mut Image),
{
    fn render(&mut self, state: &mut State, image: &mut Image) {
        self(&mut (), image)
    }
}

有什么办法可以达到这种效果?

1 个答案:

答案 0 :(得分:1)

我认为,如果您想坚持使用此设计,唯一的方法是使用auto traits并选择退出。但这需要每晚进行。一个例子:

#![feature(optin_builtin_traits)]

// Implement DummyState for everything ...
auto trait DummyState {}
// ... but opt-out for ()
impl !DummyState for () {}

trait RenderCallback<State> {
    fn render(&mut self, state: &mut State, num: u8);
}

// Implement render callback for any type that implements DummyState
impl<F, State> RenderCallback<State> for F
where
    F: FnMut(&mut State, u8),
    State: DummyState, // DummyState means any type except opted out ()
{
    fn render(&mut self, state: &mut State, num: u8) {
        self(state, num)
    }
}

// Implement render callback for (), which doesn't implement DummyState,
// so there's no overlap
impl<F> RenderCallback<()> for F
where
    F: FnMut(u8),
{
    fn render(&mut self, _state: &mut (), num: u8) {
        self(num)
    }
}

fn with_state() {
    struct MyState {
        x: u8,
    };

    println!("with_state...");
    let mut state = MyState { x: 0 };
    let mut callback = |state: &mut MyState, num: u8| {
        state.x += num;
        println!("{}", state.x);
    };
    callback.render(&mut state, 1);
    callback.render(&mut state, 2);
    callback.render(&mut state, 3);
}

fn without_state() {
    println!("without state...");
    let mut callback = |num: u8| {
        println!("{}", num);
    };
    callback.render(&mut (), 1);
    callback.render(&mut (), 2);
    callback.render(&mut (), 3);
}

fn main() {
    with_state();
    without_state();
}