如何解决这个与生命周期相关的错误?
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_readable
或 on_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
。这仅对生命周期参数有效,因为不同的生命周期参数不会导致定义多个版本的函数,这与类型参数不同。
假设我有以下内容,
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_readable
或 on_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
。这仅对生命周期参数有效,因为不同的生命周期参数不会导致定义多个版本的函数,这与类型参数不同。