You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/types/impl-trait.md
+49-51Lines changed: 49 additions & 51 deletions
Original file line number
Diff line number
Diff line change
@@ -5,64 +5,63 @@
5
5
>
6
6
> _ImplTraitTypeOneBound_ : `impl`[_TraitBound_]
7
7
8
-
`impl Trait` is the new way to specify unnamed but concrete types that
8
+
> **Edition differences**: `impl Trait` is new in the 2018 edition.
9
+
10
+
`impl Trait` provides ways to specify unnamed but concrete types that
9
11
implement a specific trait.
10
-
There are two places you can put it: argument position, and return position.
12
+
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
13
12
-
```rust,ignore
14
+
```rust
13
15
traitTrait {}
16
+
# implTraitfor () {}
14
17
15
-
// argument position
18
+
// argument position: anonymous type parameter
16
19
fnfoo(arg:implTrait) {
17
20
}
18
21
19
-
// return position
20
-
fn foo() -> impl Trait {
22
+
// return position: abstract return type
23
+
fnbar() ->implTrait {
21
24
}
22
25
```
23
26
## Anonymous type parameters
24
27
25
28
> Note: This is often called "impl Trait in argument position".
26
29
27
-
Functions can declare an argument to be an anonymous type parameter where the
28
-
caller must provide a type that has the bounds declared by the anonymous type
29
-
parameter and the function can only use the methods available by the trait
30
-
bounds of the anonymous type parameter.
30
+
Functions can use `impl` followed by a set of trait bounds to declare an argument as having an anonymous type.
31
+
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.
31
32
32
-
They are written as `impl` followed by a set of trait bounds.
33
-
In argument position, this feature is quite simple.
34
-
These two forms are almost the same:
33
+
For example, these two forms are almost equivalent:
35
34
36
35
```rust,ignore
37
36
trait Trait {}
38
37
38
+
// generic type parameter
39
39
fn foo<T: Trait>(arg: T) {
40
40
}
41
41
42
+
// impl Trait in argument position
42
43
fn foo(arg: impl Trait) {
43
44
}
44
45
```
45
46
46
-
That is, it's a slightly shorter syntax for a generic type parameter.
47
-
It means, "`arg` is an argument that takes any type that implements the `Trait` trait."
47
+
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.
48
48
49
-
However, there's also an important technical difference between `T: Trait` and `impl Trait` here.
50
-
When you write the former, you can specify the type of `T` at the call site with turbo-fish syntax as with `foo::<usize>(1)`.
51
-
In the case of `impl Trait`, if it is used anywhere in the function definition, then you can't use turbo-fish at all.
52
-
Therefore, you should be mindful that changing both from and to `impl Trait` can constitute a breaking change for the users of your code.
49
+
> **Note:**
50
+
> For function arguments, generic type parameters and `impl Trait` are not exactly equivalent.
51
+
> 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)`.
52
+
> If `impl Trait` is the type of a function argument, then the caller can't ever specify the type of that argument by using a generic argument.
53
+
>
54
+
> Therefore, changing the function signature from either one to the other can constitute a breaking change for the callers of a function.
53
55
54
56
## Abstract return types
55
57
56
58
> Note: This is often called "impl Trait in return position".
57
59
58
-
Functions, except for associated trait functions, can return an abstract
59
-
return type. These types stand in for another concrete type where the
60
-
use-site may only use the trait methods declared by the trait bounds of the
61
-
type.
62
-
63
-
They are written as `impl` followed by a set of trait bounds.
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.
64
63
65
-
Before `impl Trait`, you could do this with trait objects:
64
+
Prior to `impl Trait`, a function could express abstract return types by using [trait objects]:
You couldn't write the type of the closure, only use the `Fn` trait.
116
-
That means that the trait object is necessary. However, with `impl Trait`:
110
+
It wasn't possible to fully specify the type of the closure, only use the `Fn` trait.
111
+
That means that the trait object is necessary.
112
+
However, with `impl Trait`:
117
113
118
114
```rust
119
115
fnreturns_closure() ->implFn(i32) ->i32 {
120
116
|x|x+1
121
117
}
122
118
```
123
119
124
-
We can now return closures by value, just like any other type!
120
+
It is now possible to return closures by value, just like any other type.
125
121
126
122
## More details
127
123
@@ -132,10 +128,8 @@ Consider this function:
132
128
fn foo<T: Trait>(x: T) {
133
129
```
134
130
135
-
When you call it, you set the type, `T`.
136
-
"you" being the caller here.
137
-
This signature says "I accept any type that implements `Trait`."
138
-
("any type" == universal in the jargon)
131
+
The caller of this function determines the type, `T`.
132
+
This function signature means that the function accepts any type that implements `Trait`."
139
133
140
134
This version:
141
135
@@ -144,15 +138,15 @@ fn foo<T: Trait>() -> T {
144
138
```
145
139
146
140
is similar, but also different.
147
-
You, the caller, provide the type you want, `T`, and then the function returns it.
148
-
You can see this in Rust today with things like parse or collect:
141
+
The caller determines the return type, `T`, and the function returns it.
142
+
Examples of this include the `.parse()` or `.collect()` methods:
149
143
150
144
```rust,ignore
151
145
let x: i32 = "5".parse()?;
152
146
let x: u64 = "5".parse()?;
153
147
```
154
148
155
-
Here, `.parse` has this signature:
149
+
Here, `.parse()` has this signature:
156
150
157
151
```rust,ignore
158
152
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err> where
@@ -162,8 +156,8 @@ pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err> where
162
156
Same general idea, though with a result type and `FromStr` has an associated type... anyway, you can see how `F` is in the return position here.
163
157
So you have the ability to choose.
164
158
165
-
With `impl Trait`, you're saying "hey, some type exists that implements this trait, but I'm not gonna tell you what it is."
166
-
So now, the caller can't choose, and the function itself gets to choose.
159
+
With `impl Trait`, the function asserts that the return type will implement this trait, but the caller can't know exactly which type.
160
+
So with `impl Trait`, unlike with a generic type parameter for the return type, the caller can't choose the return type, and the function itself gets to choose.
167
161
If we tried to define parse with `Result<impl F,...` as the return type, it wouldn't work.
168
162
169
163
### Using `impl Trait` in more places
@@ -173,5 +167,9 @@ However, `impl Trait` can't be used inside implementations of traits, nor can it
173
167
Some of these restrictions will eventually be lifted.
174
168
For more information, see the [tracking issue on `impl Trait`](https://github.com/rust-lang/rust/issues/34511).
0 commit comments