Skip to content

Commit

Permalink
Fix #1060: document impl Trait on its own page and others
Browse files Browse the repository at this point in the history
  • Loading branch information
adamchalmers committed Sep 10, 2019
1 parent 37a2861 commit de659da
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 de659da

Please sign in to comment.