From de659da115e6542d9c00687bf904b44d5125c0f6 Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Tue, 10 Sep 2019 17:50:06 -0500 Subject: [PATCH] Fix #1060: document impl Trait on its own page and others --- src/SUMMARY.md | 1 + src/fn/closures/output_parameters.md | 20 +++++------ src/trait/impl_trait.md | 52 ++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 src/trait/impl_trait.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 8b27814ce4..2c55bc38ed 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/fn/closures/output_parameters.md b/src/fn/closures/output_parameters.md index 0810b281ac..e12e6049ef 100644 --- a/src/fn/closures/output_parameters.md +++ b/src/fn/closures/output_parameters.md @@ -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: @@ -21,16 +19,16 @@ dropped as soon as the function exited, leaving invalid references in the closure. ```rust,editable -fn create_fn() -> Box { +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 { +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() { @@ -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 diff --git a/src/trait/impl_trait.md b/src/trait/impl_trait.md new file mode 100644 index 0000000000..2ad3795475 --- /dev/null +++ b/src/trait/impl_trait.md @@ -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 and returns an iterator over it. +// Look how complicated its return type is! +fn combine_vecs_explicit_return_type<'a>( + v: Vec, + u: Vec, +) -> iter::Cycle, IntoIter>> { + 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, + u: Vec, +) -> impl Iterator { + 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) -> impl Iterator + 'a { + numbers + .iter() + .filter(|x| x > &&0) + .map(|x| x * 2) +} +``` \ No newline at end of file