Skip to content

Commit

Permalink
TRPL: deref coercions
Browse files Browse the repository at this point in the history
  • Loading branch information
steveklabnik committed Apr 24, 2015
1 parent 1114fcd commit acf49e6
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 5 deletions.
116 changes: 115 additions & 1 deletion src/doc/trpl/deref-coercions.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,117 @@
% `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();
```

Rust will try to dereference `f` as many times as it can to find the `foo()`
method. And since this uses `*`, it uses `Deref`.
8 changes: 4 additions & 4 deletions src/doc/trpl/method-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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`
Expand Down

0 comments on commit acf49e6

Please sign in to comment.