Skip to content

TRPL: Borrow and AsRef #24996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/trpl/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* [Concurrency](concurrency.md)
* [Error Handling](error-handling.md)
* [FFI](ffi.md)
* [Borrow and AsRef](borrow-and-asref.md)
* [Syntax and Semantics](syntax-and-semantics.md)
* [Variable Bindings](variable-bindings.md)
* [Functions](functions.md)
Expand Down
93 changes: 93 additions & 0 deletions src/doc/trpl/borrow-and-asref.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
% 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]: ../std/borrow/trait.Borrow.html
[asref]: ../std/convert/trait.AsRef.html

# Borrow

The `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` method][get] which uses `Borrow`:

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

[hashmap]: ../std/collections/struct.HashMap.html
[get]: ../std/collections/struct.HashMap.html#method.get

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

```rust,ignore
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 `&str`s when we’re searching:

```rust
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 there’s more than one
kind of borrowed value. Slices are an area where this is especially true: 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);
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could include the output here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

This will print out `a is borrowed: 5` twice.

# AsRef

The `AsRef` trait is a conversion trait. It’s used for converting some value to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, AsRef is specifically intended for generic code -- you might want to give a function signature that uses T: AsRef<str> for example. It's very much not intended for conversions on concrete types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

a reference in generic code. Like this:

```rust
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` 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` when you want to convert something to a reference directly, and
you’re writing generic code.
5 changes: 5 additions & 0 deletions src/libcollections/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ use self::Cow::*;
/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`. A given
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
///
/// `Borrow` is very similar to, but different than, `AsRef`. See
/// [the book][book] for more.
///
/// [book]: ../../book/borrow-and-asref.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrows from an owned value.
Expand Down
5 changes: 5 additions & 0 deletions src/libcore/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ use marker::Sized;

/// A cheap, reference-to-reference conversion.
///
/// `AsRef` is very similar to, but different than, `Borrow`. See
/// [the book][book] for more.
///
/// [book]: ../../book/borrow-and-asref.html
///
/// # Examples
///
/// Both `String` and `&str` implement `AsRef<str>`:
Expand Down