Reputation: 5238
I'm new to rust and I've just learned about the Borrow
trait.
From what I understand, the Borrow
trait exposes a function borrow
which works just like borrowing (i.e. &
), but you can also use it in generic constraints (which you can't do with the normal borrowing syntax).
I have this function
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where K: Borrow<Q>,
Q: Hash + Eq + ?Sized
{
let bucket = self.bucket_key(key);
self.buckets[bucket].iter().find(|&(ref ekey, _)| ekey.borrow() == key).map(|&(_, ref v)| v)
}
(I watched Jon Gjengset's video on YouTube)
And what is weird for me is that we constrain the K
type, which is defined on the struct, to act like a Borrow<Q>
.
So I was wondering what exactly this constraint says about K
and Q
.
Does it mean that we're constraining K
to behave like a Borrow<Q>
, or is K
fixed here (since it was already defined on the struct) and we're constraining Q
(and behind the scenes Rust converts it into something like Q: Unborrow<K>
or something along these lines).
I hope that I make sense. I usually do C#, where something like that doesn't make sense.
Upvotes: 1
Views: 552
Reputation: 13952
I assume you are referring to HashMap::get
.
Don't overthink it. Rust trait system is basically a kind of logic, trait bounds are like logical constraints; here the type signature says:
Q
has to be Hash
, Eq
and ?Sized
K
has to be able to be borrowed as Q
In practice, it is for convenience:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(String::from("a"), 1u32);
map.insert(String::from("b"), 2);
assert_eq!(map.get("a"), Some(&1));
}
The map
variable here is of type HashMap<String, u32>
. If it weren't for the Borrow
, you'll have to write:
map.get(&String::from("a"))
but since String
can be borrowed as str
and "a"
is of type &'static str
, you can write:
map.get("a")
The trait Borrow
documentation has more elaborated explanation.
Upvotes: 2