Skip to content

Commit f577ce9

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

File tree

1 file changed

+71
-1
lines changed

1 file changed

+71
-1
lines changed

src/doc/trpl/deref-coercions.md

+71-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,73 @@
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 convert 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.

0 commit comments

Comments
 (0)