Skip to content

Commit 81ad2cf

Browse files
authored
Merge pull request #1017 from tlyu/impl-trait
Add more content to impl-trait.md
2 parents 23ad230 + 94085bb commit 81ad2cf

File tree

1 file changed

+103
-16
lines changed

1 file changed

+103
-16
lines changed

src/types/impl-trait.md

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,120 @@
55
>
66
> _ImplTraitTypeOneBound_ : `impl` [_TraitBound_]
77
8-
## Anonymous type parameters
8+
`impl Trait` provides ways to specify unnamed but concrete types that
9+
implement a specific trait.
10+
It can appear in two sorts of places: argument position (where it can act as an anonymous type parameter to functions), and return position (where it can act as an abstract return type).
11+
12+
```rust
13+
trait Trait {}
14+
# impl Trait for () {}
915

10-
> Note: This section is a placeholder for more comprehensive reference
11-
> material.
16+
// argument position: anonymous type parameter
17+
fn foo(arg: impl Trait) {
18+
}
19+
20+
// return position: abstract return type
21+
fn bar() -> impl Trait {
22+
}
23+
```
24+
## Anonymous type parameters
1225

1326
> Note: This is often called "impl Trait in argument position".
27+
(The term "parameter" is more correct here, but "impl Trait in argument position" is the phrasing used during the development of this feature, and it remains in parts of the implementation.)
1428

15-
Functions can declare an argument to be an anonymous type parameter where the
16-
callee must provide a type that has the bounds declared by the anonymous type
17-
parameter and the function can only use the methods available by the trait
18-
bounds of the anonymous type parameter.
29+
Functions can use `impl` followed by a set of trait bounds to declare a parameter as having an anonymous type.
30+
The caller must provide a type that satisfies the bounds declared by the anonymous type parameter, and the function can only use the methods available through the trait bounds of the anonymous type parameter.
1931

20-
They are written as `impl` followed by a set of trait bounds.
32+
For example, these two forms are almost equivalent:
2133

22-
## Abstract return types
34+
```rust,ignore
35+
trait Trait {}
36+
37+
// generic type parameter
38+
fn foo<T: Trait>(arg: T) {
39+
}
40+
41+
// impl Trait in argument position
42+
fn foo(arg: impl Trait) {
43+
}
44+
```
2345

24-
> Note: This section is a placeholder for more comprehensive reference
25-
> material.
46+
That is, `impl Trait` in argument position is syntactic sugar for a generic type parameter like `<T: Trait>`, except that the type is anonymous and doesn't appear in the [_GenericParams_] list.
47+
48+
> **Note:**
49+
> For function parameters, generic type parameters and `impl Trait` are not exactly equivalent.
50+
> With a generic parameter such as `<T: Trait>`, the caller has the option to explicitly specify the generic argument for `T` at the call site using [_GenericArgs_], for example, `foo::<usize>(1)`.
51+
> If `impl Trait` is the type of *any* function parameter, then the caller can't ever provide any generic arguments when calling that function.
52+
This includes generic arguments for the return type or any const generics.
53+
>
54+
> Therefore, changing the function signature from either one to the other can constitute a breaking change for the callers of a function.
55+
56+
## Abstract return types
2657

2758
> Note: This is often called "impl Trait in return position".
2859
29-
Functions, except for associated trait functions, can return an abstract
30-
return type. These types stand in for another concrete type where the
31-
use-site may only use the trait methods declared by the trait bounds of the
32-
type.
60+
Functions can use `impl Trait` to return an abstract return type.
61+
These types stand in for another concrete type where the caller may only use the methods declared by the specified `Trait`.
62+
Each possible return value from the function must resolve to the same concrete type.
63+
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]:
68+
69+
```rust
70+
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
71+
Box::new(|x| x + 1)
72+
}
73+
```
74+
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.
77+
That means that the trait object is necessary.
78+
However, with `impl Trait`, it is possible to write this more simply:
79+
80+
```rust
81+
fn returns_closure() -> impl Fn(i32) -> i32 {
82+
|x| x + 1
83+
}
84+
```
85+
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.
90+
91+
### Differences between generics and `impl Trait` in return position
92+
93+
In argument position, `impl Trait` is very similar in semantics to a generic type parameter.
94+
However, there are significant differences between the two in return position.
95+
With `impl Trait`, unlike with a generic type parameter, the function chooses the return type, and the caller cannot choose the return type.
96+
97+
The function:
98+
99+
```rust,ignore
100+
fn foo<T: Trait>() -> T {
101+
```
102+
103+
allows the caller to determine the return type, `T`, and the function returns that type.
104+
105+
The function:
106+
107+
```rust,ignore
108+
fn foo() -> impl Trait {
109+
```
110+
111+
doesn't allow the caller to determine the return type.
112+
Instead, the function chooses the return type, but only promises that it will implement `Trait`.
113+
114+
## Limitations
33115

34-
They are written as `impl` followed by a set of trait bounds.
116+
`impl Trait` can only appear as a parameter or return type of a free or inherent function.
117+
It cannot appear inside implementations of traits, nor can it be the type of a let binding or appear inside a type alias.
35118

119+
[closures]: closure.md
120+
[_GenericArgs_]: ../paths.md#paths-in-expressions
121+
[_GenericParams_]: ../items/generics.md
36122
[_TraitBound_]: ../trait-bounds.md
123+
[trait object]: trait-object.md
37124
[_TypeParamBounds_]: ../trait-bounds.md

0 commit comments

Comments
 (0)