Questions about HashMap's get_key_value

So I'm doing a silly thingy, with a HashMap keys of Vectors of references. I probably shouldn't, but am.

During the program I wanted to get user input, find the key in the hashmap that matches, and store a reference to said key. It'd be lifetime bounded to the hashmap. I read the documentation for get_key_value, and it seemed to imply that it could be used for getting a reference to the key that the hashmap owned. But I ran into borrow checker issues.

A stripped down (and now somewhat silly) example.

use std::collections::HashMap;
use std::io::{self,Write};

fn input(prompt:&str)->String{
    io::stdout().write(prompt.as_bytes()).unwrap();
    let mut guess=String::new();
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut guess).expect("Failed to read line");
    guess.trim_end_matches(['\n','\r']).to_string()
}

fn main(){
    let r=vec![2,3,4];
    let a:HashMap<Vec<&i32>,u8>=HashMap::from_iter(r.iter().map(|a|(vec![a],1)));
    let mut c1=None;
    {
        let b:i32=input("Key:").parse().expect("That wasn't an i32");
        if let Some(aa)=a.get_key_value(&vec![&b]){
            c1=Some(aa.0);
        }
        else{println!("Not a key");}
    }
    println!("{c1:?}");

As far as I can tell, c1 should be a reference tied to a, and so it shouldn't matter that b goes out of scope.
But I got

error[E0597]: `b` does not live long enough
  --> src/main.rs:18:47
   |
17 |         let b:i32=input("Key:").parse().expect("That wasn't an i32");
   |             - binding `b` declared here
18 |         if let Some(aa)=a.get_key_value(&vec![&b]){
   |                                               ^^ borrowed value does not live long enough
...
22 |     }
   |     - `b` dropped here while still borrowed
23 |     println!("{c1:?}");
   |                -- borrow later used here

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` (bin "playground") due to 1 previous error

I messed around with

use std::collections::HashMap;
use std::io::{self,Write};

fn input(prompt:&str)->String{
    io::stdout().write(prompt.as_bytes()).unwrap();
    let mut guess=String::new();
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut guess).expect("Failed to read line");
    guess.trim_end_matches(['\n','\r']).to_string()
}

fn main(){
    let r=vec![2,3,4];
    let a:HashMap<Vec<&i32>,u8>=HashMap::from_iter(r.iter().map(|a|(vec![a],1)));
    let mut c1=None;
    {
        let b:i32=input("Key:").parse().expect("That wasn't an i32");
        if a.contains_key(&vec![&b]){
            c1=a.get_key_value(&vec![&b]).map(|(a,_)|a);
        }
        else{println!("Not a key");}
    }
    println!("{c1:?}");
}

and the Entry API but nothing seemed to work.
I settled on

unsafe{c1=a.get_key_value(&vec![&(*(&raw const b))]).map(|(a,_)|a);}

and there doesn't seem to be an issue. But I'm unsure if what I'm doing is wrong or unsound somehow.
A few friends I asked said the K:Borrow<Q> implies that &K must outlive Q. It doesn't seem like it from the documentation.
Either way, I'm somewhat confused by the "for getting a reference to a key with the same lifetime as the collection." line in the get_key_value documentation.
Also if what I'm doing is somehow unsound through some case I can't see.

This is a limitation resulting from how HashMap works using the Borrow trait. In order for your code to compile, there would need to be a implementation of Borrow that is equivalent to

impl<'a, 'b> Borrow<Vec<&'b i32>> for Vec<&'a i32> {...}

but there isn’t (and can’t be) such an implementation.

What you can do instead is use hashbrown::HashMap which allows its keys to implement the more flexible Equivalent trait.

To be a bit more concrete, there are two generic Borrow implementations for Vec<&'k i32>:

impl<T: ?Sized> Borrow<T> for T { ... }
impl<I> Borrow<[I]> for Vec<I> { ... }

When applied to Vec<&'k i32>, they act like

impl<'k> Borrow<Vec<&'k i32>> for Vec<&'k i32> { ... }
impl<'k> Borrow<[&'k i32]> for Vec<&'k i32> { ... }

Where every instance of the generic variables T or I are the same, including lifetimes.

So you can only look things up using the same lifetime (i.e. the same borrow duration).

The reflective implementation can't be overrode, but the trait itself doesn't require lifetime equivalence; with Vec<_> it's a fallout of the generic implementations. If you didn't want to use HashBrown, you could instead put a newtype around the key and supply a more lenient (with regard to lifetimes) implementation, for example.

// We use `[&'b i32]` so you don't have to create `Vec`s just for lookups.
// (You didn't need to in your OP either, but it doesn't fix the OP error.)
#[derive(PartialEq, Eq, Hash, Debug)]
struct Key<T>(Vec<T>);
impl<'k: 'b, 'b, B> Borrow<[&'b B]> for Key<&'k B> {
    fn borrow(&self) -> &[&'b B] {
        &*self.0
    }
}

// ...

if let Some(aa) = a.get_key_value(&[&b][..]) {

Thanks for explaining. I couldn't've figured out what was causing things to not work, and the newtype solution you've given feels like the sort of thing that'd never occur to me (and a bit like magic).

I appreciate the help. Both it terms of having a solution, and in that now I feel I understand Rust better.

I want to note for others like me that are confused by simple things: In my program, I=str (yes, the keys are arrays of string references. This is a silly program doing silly stuff) and so the solution wasn't working and it perplexed me until I remembered to add ?Sized. I don't know if that's the right way to deal with it, but the borrow checker isn't complaining so I think that means it's at least not dangerous.

I.e.:

//                vvvvvvvv  (we're going to utilize `B = str`)
impl<'k: 'b, 'b, B: ?Sized> Borrow<[&'b B]> for Key<&'k B> {
    fn borrow(&self) -> &[&'b B] {
        &*self.0
    }
}

Something I indeed did not think about myself.