rust/src/doc/book/borrow-and-asref.md
Steve Klabnik 024aa9a345 src/doc/trpl -> src/doc/book
The book was located under 'src/doc/trpl' because originally, it was
going to be hosted under that URL. Late in the game, before 1.0, we
decided that /book was a better one, so we changed the output, but
not the input. This causes confusion for no good reason. So we'll change
the source directory to look like the output directory, like for every
other thing in src/doc.
2015-11-19 11:30:18 -05:00

2.6 KiB
Raw Blame History

% Borrow and AsRef

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

Borrow

The Borrow trait is used when youre writing a datastructure, and you want to use either an owned or borrowed type as synonymous for some purpose.

For example, HashMap has a get method which uses Borrow:

fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
    where K: Borrow<Q>,
          Q: Hash + Eq

This signature is pretty complicated. The K parameter is what were interested in here. It refers to a parameter of the HashMap itself:

struct HashMap<K, V, S = RandomState> {

The K parameter is the type of key the HashMap uses. So, looking at the signature of get() again, we can use get() when the key implements Borrow<Q>. That way, we can make a HashMap which uses String keys, but use &strs when were 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.

For most types, when you want to take an owned or borrowed type, a &T is enough. But one area where Borrow is effective is when theres more than one kind of borrowed value. This is especially true of references and slices: you can have both an &T or a &mut T. If we wanted to accept both of these types, 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 twice.

AsRef

The AsRef trait is a conversion trait. Its 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();
}

Which should I use?

We can see how theyre kind of the same: they both deal with owned and borrowed versions of some type. However, theyre a bit different.

Choose Borrow when you want to abstract over different kinds of borrowing, or when youre building a datastructure that treats owned and borrowed values in equivalent ways, such as hashing and comparison.

Choose AsRef when you want to convert something to a reference directly, and youre writing generic code.