Borrow and AsRef

The Borrow`Borrow` and AsRef`AsRef` traits are very similar, but different. Here’s a quick refresher on what these two traits mean.

Borrow

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 main() { fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq }
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:

fn main() { struct HashMap<K, V, S = RandomState> { }
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:

fn main() { use std::collections::HashMap; let mut map = HashMap::new(); map.insert("Foo".to_string(), 42); assert_eq!(map.get("Foo"), Some(&42)); }
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 String`.

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:

fn main() { 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); }
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.

AsRef

The AsRef`AsRef` trait is a conversion trait. It’s used for converting some value to a reference in generic code. Like this:

fn main() { let s = "Hello".to_string(); fn foo<T: AsRef<str>>(s: T) { let slice = s.as_ref(); } }
let s = "Hello".to_string();

fn foo<T: AsRef<str>>(s: T) {
    let slice = s.as_ref();
}

Which should I use?

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.