Can't query by compound key containing reference

The following code does not compile, failing with `x` does not live long enough.

use std::collections::BTreeMap;

pub fn main() {
    let mut map = BTreeMap::<(i64, &i64), ()>::new();
    let mut vals = vec![0];
    vals.retain(|&x| {
        map.get_mut(&(x, &x));
        true
    });
}

Playground link

It seems this is because &(i64, &i64) cannot be borrowed as &(i64, &i64) with a different lifetime. What might be a good workaround in this situation?

unfortunately, the standard library cannot implements Borrow for every possible shapes of tuples. you can use a newtype wrapper as the key, something like:

#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
struct Key<'b>((i64, &'b i64));

impl<'a, 'b: 'a> Borrow<(i64, &'a i64)> for Key<'b> {
    fn borrow(&self) -> &(i64, &'a i64) {
        &(self.0)
    }
}

then simply change the type of map to BTreeMap::<Key<'_>, ()> should pass the borrow checker.

2 Likes

That makes sense, but it still does not compile: Rust Playground

Also, changing the get_mut to get makes the code compile, but the type signature for get_mut and get don't differ in terms of any lifetimes: Rust Playground

since Borrow is implemented, you don't need to use Key when calling get_mut(), that's the whole point of Borrow:

Thanks!