rust/src/doc/trpl/borrow-and-asref.md
Manish Goregaokar b613ef552d Rollup merge of #25580 - killercup:trpl/unify-code-blocks, r=steveklabnik
This adds strictly more information to the source files and reduces the need for customized tooling to render the book. (While this should not change the output of _rustbook_, it is very useful when rendering the sources with external tools like Pandoc.)

This only adds the language marker to "first level" code blocks (and not to code blocks in comments inside of code examples).

r? @steveklabnik
2015-05-19 18:47:15 +05:30

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.