我如何创建&使用回调函数列表?

时间:2015-03-10 04:29:38

标签: closures rust

在Rust中,我试图创建一个回调函数列表以便稍后调用:

use std::vec::Vec;

fn add_to_vec<T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: T) {
    v.push(Box::new(f));
}

fn call_b() {
    println!("Call b.");
}

#[test]
fn it_works() {
    let calls: Vec<Box<FnMut() -> ()>> = Vec::new();

    add_to_vec(&calls, || { println!("Call a."); });
    add_to_vec(&calls, call_b);

    for c in calls.drain() {
        c();
    }
}

我主要遵循建议here on how to store a closure,但是,我仍然看到一些错误:

src/lib.rs:6:12: 6:23 error: the parameter type `T` may not live long enough [E0311]
src/lib.rs:6     v.push(Box::new(f));
                        ^~~~~~~~~~~
src/lib.rs:6:23: 6:23 help: consider adding an explicit lifetime bound for `T`
src/lib.rs:5:68: 7:2 note: the parameter type `T` must be valid for the anonymous lifetime #1 defined on the block at 5:67...
src/lib.rs:5 fn add_to_vec<T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: T) {
src/lib.rs:6     v.push(Box::new(f));
src/lib.rs:7 }
src/lib.rs:6:12: 6:23 note: ...so that the type `T` will meet its required lifetime bounds
src/lib.rs:6     v.push(Box::new(f));
                        ^~~~~~~~~~~

我已尝试将功能签名更改为:

fn add_to_vec<'a, T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: &'a T) {

...但这让我:

src/lib.rs:6:12: 6:23 error: the trait `core::ops::Fn<()>` is not implemented for the type `&T` [E0277]
src/lib.rs:6     v.push(Box::new(f));
                        ^~~~~~~~~~~
error: aborting due to previous error
src/lib.rs:6:12: 6:23 error: the trait `core::ops::Fn<()>` is not implemented for the type `&T` [E0277]
src/lib.rs:6     v.push(Box::new(f));
                        ^~~~~~~~~~~
src/lib.rs:18:24: 18:51 error: mismatched types:
 expected `&_`,
    found `[closure src/lib.rs:18:24: 18:51]`
(expected &-ptr,
    found closure) [E0308]
src/lib.rs:18     add_to_vec(&calls, || { println!("Call a."); });
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~

(我可以通过添加&来纠正的最后一个错误;虽然我认为这是我应该需要的,因为add_to_vec最终将拥有闭包,因此需要借用它,我不完全确定。)

1 个答案:

答案 0 :(得分:3)

您的代码存在一些问题。这是一个完全固定的版本:

use std::vec::Vec;

fn add_to_vec<'a, T: FnMut() + 'a>(v: &mut Vec<Box<FnMut() + 'a>>, f: T) {
    v.push(Box::new(f));
}

fn call_b() {
    println!("Call b.");
}

#[test]
fn it_works() {
    let mut calls: Vec<Box<FnMut()>> = Vec::new();

    add_to_vec(&mut calls, || { println!("Call a."); });
    add_to_vec(&mut calls, call_b);

    for mut c in calls.drain() {
        c();
    }
}

生命周期问题是盒装函数对象必须具有共同的基本生命周期;如果您只是编写通用约束T: FnMut(),则假定只需要函数调用就可以生存,而不再需要。因此,需要向它添加两件事:泛型参数T必须约束到指定的生命周期,并且为了将其存储在向量中,特征对象类型必须同样受到约束,如{{1 }}。这样它们就可以匹配并确保内存安全,因此编译器可以通过它。顺便说一下,Box<FnMut() + 'a>的{​​{1}}部分是多余的。

需要进行的其余修复是插入一些-> ();为了推送向量,你自然需要一个可变引用,因此FnMut() -> ()mut会发生变化,并且为了对&&mut进行可变引用绑定必须calls