Skip to content

Fix #1060: add page on Impl Trait #1251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
- [Operator Overloading](trait/ops.md)
- [Drop](trait/drop.md)
- [Iterators](trait/iter.md)
- [impl Trait](trait/impl_trait.md)
- [Clone](trait/clone.md)

- [macro_rules!](macros.md)
Expand Down
20 changes: 9 additions & 11 deletions src/fn/closures/output_parameters.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# As output parameters

Closures as input parameters are possible, so returning closures as
output parameters should also be possible. However, returning closure types
are problematic because Rust currently only supports returning concrete
(non-generic) types. Anonymous closure types are, by definition, unknown
and so returning a closure is only possible by making it concrete. This
can be done via boxing.
output parameters should also be possible. However, anonymous
closure types are, by definition, unknown, so we have to use
`impl Trait` to return them.

The valid traits for returns are slightly different than before:

Expand All @@ -21,16 +19,16 @@ dropped as soon as the function exited, leaving invalid references in the
closure.

```rust,editable
fn create_fn() -> Box<Fn()> {
fn create_fn() -> impl Fn() {
let text = "Fn".to_owned();

Box::new(move || println!("This is a: {}", text))
move || println!("This is a: {}", text)
}

fn create_fnmut() -> Box<FnMut()> {
fn create_fnmut() -> impl FnMut() {
let text = "FnMut".to_owned();

Box::new(move || println!("This is a: {}", text))
move || println!("This is a: {}", text)
}

fn main() {
Expand All @@ -44,10 +42,10 @@ fn main() {

### See also:

[Boxing][box], [`Fn`][fn], [`FnMut`][fnmut], and [Generics][generics].
[`Fn`][fn], [`FnMut`][fnmut], [Generics][generics] and [impl Trait][impltrait].

[box]: ../../std/box.md
[fn]: https://doc.rust-lang.org/std/ops/trait.Fn.html
[fnmut]: https://doc.rust-lang.org/std/ops/trait.FnMut.html
[fnbox]: https://doc.rust-lang.org/std/boxed/trait.FnBox.html
[generics]: ../../generics.md
[impltrait]: ../../traits/impl_trait.md
52 changes: 52 additions & 0 deletions src/trait/impl_trait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# impl Trait

If your function returns a type that implements `MyTrait`, you can write its return type as `-> impl MyTrait`. This can help simplify your type signatures quite a lot!

```rust,editable
use std::iter;
use std::vec::IntoIter;

// This function combines two Vec<i32> and returns an iterator over it.
// Look how complicated its return type is!
fn combine_vecs_explicit_return_type<'a>(
v: Vec<i32>,
u: Vec<i32>,
) -> iter::Cycle<iter::Chain<IntoIter<i32>, IntoIter<i32>>> {
v.into_iter().chain(u.into_iter()).cycle()
}

// This is the exact same function, but its return type uses `impl Trait`.
// Look how much simpler it is!
fn combine_vecs<'a>(
v: Vec<i32>,
u: Vec<i32>,
) -> impl Iterator<Item=i32> {
v.into_iter().chain(u.into_iter()).cycle()
}
```

More importantly, some Rust types can't be written out. For example, every closure has its own unnamed concrete type. Before `impl Trait` syntax, you had to allocate on the heap in order to return a closure. But now you can do it all statically, like this:

```rust,editable
// Returns a function that adds `y` to its input
fn make_adder_function(y: i32) -> impl Fn(i32) -> i32 {
let closure = move |x: i32| { x + y };
closure
}

fn main() {
let plus_one = make_adder_function(1);
assert_eq!(plus_one(2), 3);
}
```

You can also use `impl Trait` to return an iterator that uses `map` or `filter` closures! This makes using `map` and `filter` easier. Because closure types don't have names, you can't write out an explicit return type if your function returns iterators with closures. But with `impl Trait` you can do this easily:

```rust,editable
fn double_positives<'a>(numbers: &'a Vec<i32>) -> impl Iterator<Item = i32> + 'a {
numbers
.iter()
.filter(|x| x > &&0)
.map(|x| x * 2)
}
```