Skip to content

Commit

Permalink
Merge pull request #1251 from adamchalmers/achalmers/impl-trait
Browse files Browse the repository at this point in the history
Fix #1060: add page on Impl Trait
  • Loading branch information
marioidival authored Sep 11, 2019
2 parents ec73fc3 + de659da commit 9040387
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 11 deletions.
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)
}
```

0 comments on commit 9040387

Please sign in to comment.