The Borrow
`Borrow` and AsRef
`AsRef` traits are very similar, but
different. Here’s a quick refresher on what these two traits mean.
The Borrow
`Borrow` trait is used when you’re writing a datastructure, and you want to
use either an owned or borrowed type as synonymous for some purpose.
For example, HashMap
`HashMap` has a get
`get` method which uses Borrow
`Borrow`:
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
This signature is pretty complicated. The K
`Kparameter is what we’re interested in here. It refers to a parameter of the
` parameter is what we’re interested
in here. It refers to a parameter of the HashMap
`HashMap` itself:
struct HashMap<K, V, S = RandomState> {
The K
`Kparameter is the type of _key_ the
` parameter is the type of key the HashMap
`HashMapuses. So, looking at the signature of
` uses. So, looking at
the signature of get()
`get()again, we can use
` again, we can use get()
`get()when the key implements
` when the key implements
Borrow<Q>
`Borrow. That way, we can make a
`. That way, we can make a HashMap
`HashMapwhich uses
` which uses String
`Stringkeys, but use
` keys,
but use &str
`&str`s when we’re searching:
use std::collections::HashMap; let mut map = HashMap::new(); map.insert("Foo".to_string(), 42); assert_eq!(map.get("Foo"), Some(&42));
This is because the standard library has impl Borrow<str> for String
`impl Borrow
For most types, when you want to take an owned or borrowed type, a &T
`&Tis enough. But one area where
` is
enough. But one area where Borrow
`Borrowis effective is when there’s more than one kind of borrowed value. Slices are an area where this is especially true: you can have both an
` is effective is when there’s more than one
kind of borrowed value. Slices are an area where this is especially true: you
can have both an &[T]
`&[T]or a
` or a &mut [T]
`&mut [T]. If we wanted to accept both of these types,
`. If we wanted to accept both of these
types, Borrow
`Borrow` is up for it:
use std::borrow::Borrow; use std::fmt::Display; fn foo<T: Borrow<i32> + Display>(a: T) { println!("a is borrowed: {}", a); } let mut i = 5; foo(&i); foo(&mut i);
This will print out a is borrowed: 5
`a is borrowed: 5` twice.
The AsRef
`AsRef` trait is a conversion trait. It’s used for converting some value to
a reference in generic code. Like this:
let s = "Hello".to_string(); fn foo<T: AsRef<str>>(s: T) { let slice = s.as_ref(); }
We can see how they’re kind of the same: they both deal with owned and borrowed versions of some type. However, they’re a bit different.
Choose Borrow
`Borrow` when you want to abstract over different kinds of borrowing, or
when you’re building a datastructure that treats owned and borrowed values in
equivalent ways, such as hashing and comparison.
Choose AsRef
`AsRef` when you want to convert something to a reference directly, and
you’re writing generic code.