Reputation: 44256
Say I have the following,
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
is supposed to be a helper function for adding an "FD handler"; here, it's going to get passed a closure (adder
) that will set either on_readable
or on_writable
, depending on which handler is being added. add_fd_handler
's job is simply doing the hash table lookup, and inserting an empty entry if required. However:
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 },
The error about occ_e
only shows up if I try to use it with adder(false, entry)
! Rust claims occ_e
"does not live long enough", but it's only being used right there in that branch of the match
, so how can that be?
My best guess presently is that the closure's second arg, as &'a mut
is what's the issue here; my reference in occ_e
isn't 'a
, it's something shorter (the unspecified lifetime on hash_entry
, I think, but I don't know how to notate that).
Upvotes: 0
Views: 88
Reputation: 65752
Let the compiler infer the proper lifetime instead:
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,
}),
);
*/
}
};
}
The problem is that you're letting the caller determine a lifetime for the callback, but you then invoke the callback with a mutable reference to a local variable. The caller couldn't possibly know about the lifetime of that local variable, so the compiler assumes that 'a
must outlive the current function. Yet, entry
does not outlive the function, which is why you get an error.
The declaration T: Fn(bool, &mut EpollFdEventHandler)
is equivalent to T: for<'a, 'b> Fn(bool, &'a mut EpollFdEventHandler<'b>)
. The for
keyword in this context allows you to declare that T
must implement Fn
for any value of the specified lifetime parameters. This is only valid for lifetime parameters, because different lifetime parameters do not cause multiple versions of a function to be defined, unlike for type parameters.
Upvotes: 1