about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSteve Klabnik <steve@steveklabnik.com>2015-04-23 11:35:37 -0400
committerSteve Klabnik <steve@steveklabnik.com>2015-04-24 18:39:31 -0400
commitd70a9945365cbfeab79040d0292a8f41e62c5486 (patch)
treee0f7ccc47b4515aac8665ed4296e5b432cfbfd95
parent1114fcd945f6e979660053aeed561bcfb5da669e (diff)
TRPL: deref coercions
-rw-r--r--src/doc/trpl/deref-coercions.md118
-rw-r--r--src/doc/trpl/method-syntax.md8
2 files changed, 121 insertions, 5 deletions
diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md
index afacd304055..b7011100971 100644
--- a/src/doc/trpl/deref-coercions.md
+++ b/src/doc/trpl/deref-coercions.md
@@ -1,3 +1,119 @@
 % `Deref` coercions
 
-Coming soon!
+The standard library provides a special trait, [`Deref`][deref]. It’s normally
+used to overload `*`, the dereference operator:
+
+```rust
+use std::ops::Deref;
+
+struct DerefExample<T> {
+    value: T,
+}
+
+impl<T> Deref for DerefExample<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.value
+    }
+}
+
+fn main() {
+    let x = DerefExample { value: 'a' };
+    assert_eq!('a', *x);
+}
+```
+
+[deref]: ../std/ops/trait.Deref.html
+
+This is useful for writing custom pointer types. However, there’s a language
+feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a
+type `U`, and it implements `Deref<Target=T>`, values of `&U` will
+automatically coerce to a `&T`. Here’s an example:
+
+```rust
+fn foo(s: &str) {
+    // borrow a string for a second
+}
+
+// String implements Deref<Target=str>
+let owned = "Hello".to_string();
+
+// therefore, this works:
+foo(&owned);
+```
+
+Using an ampersand in front of a value takes a reference to it. So `owned` is a
+`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for
+String`, `&String` will deref to `&str`, which `foo()` takes.
+
+That’s it. This rule is one of the only places in which Rust does an automatic
+conversion for you, but it adds a lot of flexibility. For example, the `Rc<T>`
+type implements `Deref<Target=T>`, so this works:
+
+```rust
+use std::rc::Rc;
+
+fn foo(s: &str) {
+    // borrow a string for a second
+}
+
+// String implements Deref<Target=str>
+let owned = "Hello".to_string();
+let counted = Rc::new(owned);
+
+// therefore, this works:
+foo(&counted);
+```
+
+All we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the
+`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
+didn’t change, but works just as well with either type. This example has two
+conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
+this as many times as possible until the types match.
+
+Another very common implementation provided by the standard library is:
+
+```rust
+fn foo(s: &[i32]) {
+    // borrow a slice for a second
+}
+
+// Vec<T> implements Deref<Target=[T]>
+let owned = vec![1, 2, 3];
+
+foo(&owned);
+```
+
+Vectors can `Deref` to a slice.
+
+## Deref and method calls
+
+`Deref` will also kick in when calling a method. In other words, these are
+the same two things in Rust:
+
+```rust
+struct Foo;
+
+impl Foo {
+    fn foo(&self) { println!("Foo"); }
+}
+
+let f = Foo;
+
+f.foo();
+```
+
+Even though `f` isn’t a reference, and `foo` takes `&self`, this works.
+That’s because these things are the same:
+
+```rust,ignore
+f.foo();
+(&f).foo();
+(&&f).foo();
+(&&&&&&&&f).foo();
+```
+
+A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo`
+called, because the compiler will insert as many * operations as necessary to
+get it right. And since it’s inserting `*`s, that uses `Deref`.
diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md
index 5853f3d679c..1445d39fe87 100644
--- a/src/doc/trpl/method-syntax.md
+++ b/src/doc/trpl/method-syntax.md
@@ -18,7 +18,7 @@ foo.bar().baz();
 Luckily, as you may have guessed with the leading question, you can! Rust provides
 the ability to use this ‘method call syntax’ via the `impl` keyword.
 
-## Method calls
+# Method calls
 
 Here’s how it works:
 
@@ -83,7 +83,7 @@ impl Circle {
 }
 ```
 
-## Chaining method calls
+# Chaining method calls
 
 So, now we know how to call a method, such as `foo.bar()`. But what about our
 original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
@@ -127,7 +127,7 @@ fn grow(&self) -> Circle {
 We just say we’re returning a `Circle`. With this method, we can grow a new
 circle to any arbitrary size.
 
-## Static methods
+# Static methods
 
 You can also define methods that do not take a `self` parameter. Here’s a
 pattern that’s very common in Rust code:
@@ -158,7 +158,7 @@ This ‘static method’ builds a new `Circle` for us. Note that static methods
 are called with the `Struct::method()` syntax, rather than the `ref.method()`
 syntax.
 
-## Builder Pattern
+# Builder Pattern
 
 Let’s say that we want our users to be able to create Circles, but we will
 allow them to only set the properties they care about. Otherwise, the `x`