Skip to content

Commit 4531218

Browse files
committed
impl-trait: condense return type examples
Use only the closure example to illustrate the difference between returning trait objects vs `impl Trait`. Also mention usefulness in returning iterators.
1 parent ec1ee92 commit 4531218

File tree

1 file changed

+12
-43
lines changed

1 file changed

+12
-43
lines changed

src/types/impl-trait.md

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -61,63 +61,32 @@ Functions can use `impl Trait` to return an abstract return type.
6161
These types stand in for another concrete type where the caller may only use the methods declared by the specified `Trait`.
6262
Each possible return value from the function must resolve to the same concrete type.
6363

64-
Prior to `impl Trait`, a function could express abstract return types by using [trait objects]:
65-
66-
```rust
67-
trait Trait {}
68-
69-
impl Trait for i32 {}
70-
71-
fn returns_a_trait_object() -> Box<dyn Trait> {
72-
Box::new(5)
73-
}
74-
```
75-
76-
This has some drawbacks: constructing `Box<T>` involves a heap allocation, and the `dyn Trait` will use dynamic dispatch on its methods.
77-
However, this function only returns one possible type here: the `Box<i32>`.
78-
This means incurring the costs of dynamic dispatch, even though the return type cannot vary.
79-
80-
With `impl Trait`, the code above could be written like this:
81-
82-
```rust
83-
trait Trait {}
84-
85-
impl Trait for i32 {}
86-
87-
fn returns_a_trait_object() -> impl Trait {
88-
5
89-
}
90-
```
91-
92-
There is no `Box<T>`, no trait object, and no dynamic dispatch.
93-
However, the function can still can obscure the `i32` return type.
94-
95-
With `i32`, this might not seem very useful.
96-
There is one major place in Rust where this is much more useful: closures.
97-
98-
### `impl Trait` and closures
99-
100-
In Rust, [closures] have a unique, un-writable type.
101-
However, they do implement the `Fn` family of traits.
102-
This means that previously, the only way to return a closure from a function was to use a trait object:
64+
`impl Trait` in return position allows a function to return an unboxed abstract type.
65+
This is particularly useful with [closures] and iterators.
66+
For example, closures have a unique, un-writable type.
67+
Previously, the only way to return a closure from a function was to use a [trait object]:
10368

10469
```rust
10570
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
10671
Box::new(|x| x + 1)
10772
}
10873
```
10974

110-
It wasn't possible to fully specify the type of the closure, only use the `Fn` trait.
75+
This could incur performance penalties from heap allocation and dynamic dispatch.
76+
It wasn't possible to fully specify the type of the closure, only to use the `Fn` trait.
11177
That means that the trait object is necessary.
112-
However, with `impl Trait`:
78+
However, with `impl Trait`, it is possible to write this more simply:
11379

11480
```rust
11581
fn returns_closure() -> impl Fn(i32) -> i32 {
11682
|x| x + 1
11783
}
11884
```
11985

120-
It is now possible to return closures by value, just like any other type.
86+
which also avoids the drawbacks of using a boxed trait object.
87+
88+
Similarly, the concrete types of iterators could become very complex, incorporating the types of all previous iterators in a chain.
89+
Returning `impl Iterator` means that a function only exposes the `Iterator` trait as a bound on its return type, instead of explicitly specifying all of the other iterator types involved.
12190

12291
### Differences between generics and `impl Trait` in return position
12392

@@ -151,5 +120,5 @@ It cannot appear inside implementations of traits, nor can it be the type of a l
151120
[_GenericArgs_]: ../paths.md#paths-in-expressions
152121
[_GenericParams_]: ../items/generics.md
153122
[_TraitBound_]: ../trait-bounds.md
154-
[trait objects]: trait-object.md
123+
[trait object]: trait-object.md
155124
[_TypeParamBounds_]: ../trait-bounds.md

0 commit comments

Comments
 (0)