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

How to solve this lifetime-related error?

假设我有以下内容,

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 handler" 的辅助函数;在这里,它将传递一个闭包 (adder),该闭包将设置 on_readableon_writable,具体取决于添加的处理程序。 add_fd_handler 的工作只是进行散列 table 查找,并在需要时插入一个空条目。然而:

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) 一起使用时才会出现! Rust 声称 occ_e "does not live long enough",但它只在 match 的那个分支中使用,那怎么可能呢?

我目前的最佳猜测是闭包的第二个参数,因为&'a mut是这里的问题所在;我在 occ_e 中的引用不是 'a,它更短(hash_entry 上未指定的生命周期,我想,但我不知道如何表示)。

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

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。这仅对生命周期参数有效,因为不同的生命周期参数不会导致定义多个版本的函数,这与类型参数不同。