如何解决这个与生命周期有关的错误?

时间:2015-10-19 02:59:19

标签: rust lifetime

说我有以下内容,

type EpollEventCallback<'a> = FnMut(c_int) + Send + Sync + 'a;

struct EpollFdEventHandler<'a> {
    on_readable: Option<Box<EpollEventCallback<'a>>>,
    on_writable: Option<Box<EpollEventCallback<'a>>>,
}

// Map from c_int -> EpollFdEventHandler.
type EpollEventHandlerMap<'a> = collections::HashMap<c_int, EpollFdEventHandler<'a>>;

fn add_fd_handler
        <'a, T: Fn(bool, &'a mut EpollFdEventHandler<'a>)>(
        map: &'a mut EpollEventHandlerMap<'a>,
        fd: c_int,
        adder: T)
{
    let mut hash_entry: hash_map::Entry<'a, _, _> = map.entry(fd);
    match hash_entry {
        hash_map::Entry::Occupied(ref mut occ_e) => {
            let entry: &mut EpollFdEventHandler<'a> = occ_e.get_mut();
            adder(false, entry);
        },
        hash_map::Entry::Vacant(vac_e) => {
            /*
            adder(
                true,
                vac_e.insert(EpollFdEventHandler {
                    on_readable: None,
                    on_writable: None,
                }),
            );
            */
        }
    };
}

add_fd_handler应该是添加“FD处理程序”的辅助函数;在这里,它将传递一个闭包(adder),它将设置on_readableon_writable,具体取决于要添加的处理程序。 add_fd_handler的工作就是简单地进行哈希表查找,并在需要时插入空条目。但是:

src/event_loop.rs:85:35: 85:48 error: `(hash_entry:std::collections::hash::map::Occupied).0` does not live long enough
src/event_loop.rs:85         hash_map::Entry::Occupied(ref mut occ_e) => {
                                                       ^~~~~~~~~~~~~
src/event_loop.rs:82:1: 101:2 note: reference must be valid for the lifetime 'a as defined on the block at 82:0...
src/event_loop.rs:82 {
src/event_loop.rs:83     let mut hash_entry: hash_map::Entry<'a, _, _> = map.entry(fd);
src/event_loop.rs:84     match hash_entry {
src/event_loop.rs:85         hash_map::Entry::Occupied(ref mut occ_e) => {
src/event_loop.rs:86             let entry: &mut EpollFdEventHandler<'a> = occ_e.get_mut();
src/event_loop.rs:87             adder(false, entry);
                     ...
src/event_loop.rs:83:67: 101:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 83:66
src/event_loop.rs:83     let mut hash_entry: hash_map::Entry<'a, _, _> = map.entry(fd);
src/event_loop.rs:84     match hash_entry {
src/event_loop.rs:85         hash_map::Entry::Occupied(ref mut occ_e) => {
src/event_loop.rs:86             let entry: &mut EpollFdEventHandler<'a> = occ_e.get_mut();
src/event_loop.rs:87             adder(false, entry);
src/event_loop.rs:88         },

如果我尝试将occ_e用于adder(false, entry),则只显示occ_e的错误! Rust声明match“活得不够长”,但它只是在&'a mut的那个分支中使用,那怎么可能呢?

我的最佳猜测是关闭的第二个arg,occ_e就是这里的问题;我在'a中的引用不是hash_entry,它更短({{1}}上未指定的生命周期,我想,但我不知道如何记录这一点。)

1 个答案:

答案 0 :(得分:1)

让编译器推断出正确的生命周期:

fn add_fd_handler
        <T: Fn(bool, &mut EpollFdEventHandler)>(
        map: &mut EpollEventHandlerMap,
        fd: c_int,
        adder: T)
{
    let mut hash_entry = map.entry(fd);
    match hash_entry {
        hash_map::Entry::Occupied(ref mut occ_e) => {
            let entry = occ_e.get_mut();
            adder(false, entry);
        },
        hash_map::Entry::Vacant(vac_e) => {
            /*
            adder(
                true,
                vac_e.insert(EpollFdEventHandler {
                    on_readable: None,
                    on_writable: None,
                }),
            );
            */
        }
    };
}

问题在于您让调用者确定回调的生命周期,但是然后使用对局部变量的可变引用来调用回调。调用者不可能知道该局部变量的生命周期,因此编译器假定'a必须比当前函数寿命更长。然而,entry并不比这个功能更长,这就是你得到错误的原因。

声明T: Fn(bool, &mut EpollFdEventHandler)相当于T: for<'a, 'b> Fn(bool, &'a mut EpollFdEventHandler<'b>)。此上下文中的for关键字允许您声明T必须为指定生命周期参数的任何值实现Fn。这仅适用于生命周期参数,因为不同的生命周期参数不会导致定义函数的多个版本,这与类型参数不同。