TRPL: Borrow and AsRef
These two traits are commonly confused. As such, explain the difference. Fixes #24163
This commit is contained in:
parent
0ad202671f
commit
e780fb270c
4 changed files with 104 additions and 0 deletions
|
|
@ -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)
|
||||
|
|
|
|||
93
src/doc/trpl/borrow-and-asref.md
Normal file
93
src/doc/trpl/borrow-and-asref.md
Normal file
|
|
@ -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);
|
||||
```
|
||||
|
||||
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
|
||||
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.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>`:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue