Skip to content

Commit ec1ee92

Browse files
committed
impl-trait: generics vs impl Trait as return
Rework "More details" to focus on the differences between `impl Trait` and generic type parameters in return position. Delete the `.parse()` examples because they're somewhat verbose for a reference.
1 parent 48d970e commit ec1ee92

File tree

1 file changed

+10
-28
lines changed

1 file changed

+10
-28
lines changed

src/types/impl-trait.md

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -119,46 +119,28 @@ fn returns_closure() -> impl Fn(i32) -> i32 {
119119

120120
It is now possible to return closures by value, just like any other type.
121121

122-
## More details
122+
### Differences between generics and `impl Trait` in return position
123123

124-
The above is all you need to know to get going with `impl Trait`, but for some more nitty-gritty details: type parameters and `impl Trait` work slightly differently when they're in argument position versus return position.
125-
Consider this function:
124+
In argument position, `impl Trait` is very similar in semantics to a generic type parameter.
125+
However, there are significant differences between the two in return position.
126+
With `impl Trait`, unlike with a generic type parameter, the function chooses the return type, and the caller cannot choose the return type.
126127

127-
```rust,ignore
128-
fn foo<T: Trait>(x: T) {
129-
```
130-
131-
The caller of this function determines the type, `T`.
132-
This function signature means that the function accepts any type that implements `Trait`."
133-
134-
This version:
128+
The function:
135129

136130
```rust,ignore
137131
fn foo<T: Trait>() -> T {
138132
```
139133

140-
is similar, but also different.
141-
The caller determines the return type, `T`, and the function returns it.
142-
Examples of this include the `.parse()` or `.collect()` methods:
134+
allows the caller to determine the return type, `T`, and the function returns that type.
143135

144-
```rust,ignore
145-
let x: i32 = "5".parse()?;
146-
let x: u64 = "5".parse()?;
147-
```
148-
149-
Here, `.parse()` has this signature:
136+
The function:
150137

151138
```rust,ignore
152-
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err> where
153-
F: FromStr,
139+
fn foo() -> impl Trait {
154140
```
155141

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.
157-
So you have the ability to choose.
158-
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.
161-
If we tried to define parse with `Result<impl F,...` as the return type, it wouldn't work.
142+
doesn't allow the caller to determine the return type.
143+
Instead, the function chooses the return type, but only promises that it will implement `Trait`.
162144

163145
## Limitations
164146

0 commit comments

Comments
 (0)