]> git.lizzy.rs Git - rust.git/commitdiff
TRPL: Borrow and AsRef
authorSteve Klabnik <steve@steveklabnik.com>
Thu, 30 Apr 2015 18:40:38 +0000 (14:40 -0400)
committerSteve Klabnik <steve@steveklabnik.com>
Tue, 12 May 2015 14:53:50 +0000 (10:53 -0400)
These two traits are commonly confused. As such, explain the difference.

Fixes #24163

src/doc/trpl/SUMMARY.md
src/doc/trpl/borrow-and-asref.md [new file with mode: 0644]
src/libcollections/borrow.rs
src/libcore/convert.rs

index de7ded76280f6f103350a2105f2492d86eec7700..3f97928a56e3f067af823d1939ea8d85cf779aef 100644 (file)
@@ -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)
diff --git a/src/doc/trpl/borrow-and-asref.md b/src/doc/trpl/borrow-and-asref.md
new file mode 100644 (file)
index 0000000..f5f314f
--- /dev/null
@@ -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.
index 7332bf4670ae58efd9ce4c42a7143b2e6fc6d31c..a86a4b4215f23ff2b927b944fee0201a696a8f2d 100644 (file)
 /// 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.
index da6ac6bd752bfa3bb349b433f4081d6c35b60748..f6987c1966493843c25c768fad1a9d5aaf8f1f7e 100644 (file)
 
 /// 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>`: