Skip to content

Commit acf49e6

Browse files
committed
TRPL: deref coercions
1 parent 1114fcd commit acf49e6

File tree

2 files changed

+119
-5
lines changed

2 files changed

+119
-5
lines changed

src/doc/trpl/deref-coercions.md

+115-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,117 @@
11
% `Deref` coercions
22

3-
Coming soon!
3+
The standard library provides a special trait, [`Deref`][deref]. It’s normally
4+
used to overload `*`, the dereference operator:
5+
6+
```rust
7+
use std::ops::Deref;
8+
9+
struct DerefExample<T> {
10+
value: T,
11+
}
12+
13+
impl<T> Deref for DerefExample<T> {
14+
type Target = T;
15+
16+
fn deref(&self) -> &T {
17+
&self.value
18+
}
19+
}
20+
21+
fn main() {
22+
let x = DerefExample { value: 'a' };
23+
assert_eq!('a', *x);
24+
}
25+
```
26+
27+
[deref]: ../std/ops/trait.Deref.html
28+
29+
This is useful for writing custom pointer types. However, there’s a language
30+
feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a
31+
type `U`, and it implements `Deref<Target=T>`, values of `&U` will
32+
automatically coerce to a `&T`. Here’s an example:
33+
34+
```rust
35+
fn foo(s: &str) {
36+
// borrow a string for a second
37+
}
38+
39+
// String implements Deref<Target=str>
40+
let owned = "Hello".to_string();
41+
42+
// therefore, this works:
43+
foo(&owned);
44+
```
45+
46+
Using an ampersand in front of a value takes a reference to it. So `owned` is a
47+
`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for
48+
String`, `&String` will deref to `&str`, which `foo()` takes.
49+
50+
That’s it. This rule is one of the only places in which Rust does an automatic
51+
conversion for you, but it adds a lot of flexibility. For example, the `Rc<T>`
52+
type implements `Deref<Target=T>`, so this works:
53+
54+
```rust
55+
use std::rc::Rc;
56+
57+
fn foo(s: &str) {
58+
// borrow a string for a second
59+
}
60+
61+
// String implements Deref<Target=str>
62+
let owned = "Hello".to_string();
63+
let counted = Rc::new(owned);
64+
65+
// therefore, this works:
66+
foo(&counted);
67+
```
68+
69+
All we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the
70+
`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
71+
didn’t change, but works just as well with either type. This example has two
72+
conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
73+
this as many times as possible until the types match.
74+
75+
Another very common implementation provided by the standard library is:
76+
77+
```rust
78+
fn foo(s: &[i32]) {
79+
// borrow a slice for a second
80+
}
81+
82+
// Vec<T> implements Deref<Target=[T]>
83+
let owned = vec![1, 2, 3];
84+
85+
foo(&owned);
86+
```
87+
88+
Vectors can `Deref` to a slice.
89+
90+
## Deref and method calls
91+
92+
`Deref` will also kick in when calling a method. In other words, these are
93+
the same two things in Rust:
94+
95+
```rust
96+
struct Foo;
97+
98+
impl Foo {
99+
fn foo(&self) { println!("Foo"); }
100+
}
101+
102+
let f = Foo;
103+
104+
f.foo();
105+
```
106+
107+
Even though `f` isn’t a reference, and `foo` takes `&self`, this works.
108+
That’s because these things are the same:
109+
110+
```rust,ignore
111+
f.foo();
112+
(*f).foo();
113+
(******f).foo();
114+
```
115+
116+
Rust will try to dereference `f` as many times as it can to find the `foo()`
117+
method. And since this uses `*`, it uses `Deref`.

src/doc/trpl/method-syntax.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ foo.bar().baz();
1818
Luckily, as you may have guessed with the leading question, you can! Rust provides
1919
the ability to use this ‘method call syntax’ via the `impl` keyword.
2020

21-
## Method calls
21+
# Method calls
2222

2323
Here’s how it works:
2424

@@ -83,7 +83,7 @@ impl Circle {
8383
}
8484
```
8585

86-
## Chaining method calls
86+
# Chaining method calls
8787

8888
So, now we know how to call a method, such as `foo.bar()`. But what about our
8989
original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
@@ -127,7 +127,7 @@ fn grow(&self) -> Circle {
127127
We just say we’re returning a `Circle`. With this method, we can grow a new
128128
circle to any arbitrary size.
129129

130-
## Static methods
130+
# Static methods
131131

132132
You can also define methods that do not take a `self` parameter. Here’s a
133133
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
158158
are called with the `Struct::method()` syntax, rather than the `ref.method()`
159159
syntax.
160160

161-
## Builder Pattern
161+
# Builder Pattern
162162

163163
Let’s say that we want our users to be able to create Circles, but we will
164164
allow them to only set the properties they care about. Otherwise, the `x`

0 commit comments

Comments
 (0)