Skip to content

TRPL: deref coercions #24722

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
Apr 25, 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
118 changes: 117 additions & 1 deletion src/doc/trpl/deref-coercions.md
Original file line number Diff line number Diff line change
@@ -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:
Copy link
Member

Choose a reason for hiding this comment

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

Which 'two things' is this referring to?


```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`.
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