]> git.proxmox.com Git - rustc.git/blob - src/doc/rust-by-example/src/trait/impl_trait.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / rust-by-example / src / trait / impl_trait.md
1 # `impl Trait`
2
3 `impl Trait` can be used in two locations:
4
5 1. as an argument type
6 2. as a return type
7
8 ## As an argument type
9
10 If your function is generic over a trait but you don't mind the specific type, you can simplify the function declaration using `impl Trait` as the type of the argument.
11
12 For example, consider the following code:
13
14 ```rust,editable
15 fn parse_csv_document<R: std::io::BufRead>(src: R) -> std::io::Result<Vec<Vec<String>>> {
16 src.lines()
17 .map(|line| {
18 // For each line in the source
19 line.map(|line| {
20 // If the line was read successfully, process it, if not, return the error
21 line.split(',') // Split the line separated by commas
22 .map(|entry| String::from(entry.trim())) // Remove leading and trailing whitespace
23 .collect() // Collect all strings in a row into a Vec<String>
24 })
25 })
26 .collect() // Collect all lines into a Vec<Vec<String>>
27 }
28 ```
29
30 `parse_csv_document` is generic, allowing it to take any type which implements BufRead, such as `BufReader<File>` or `[u8]`,
31 but it's not important what type `R` is, and `R` is only used to declare the type of `src`, so the function can also be written as:
32
33 ```rust,editable
34 fn parse_csv_document(src: impl std::io::BufRead) -> std::io::Result<Vec<Vec<String>>> {
35 src.lines()
36 .map(|line| {
37 // For each line in the source
38 line.map(|line| {
39 // If the line was read successfully, process it, if not, return the error
40 line.split(',') // Split the line separated by commas
41 .map(|entry| String::from(entry.trim())) // Remove leading and trailing whitespace
42 .collect() // Collect all strings in a row into a Vec<String>
43 })
44 })
45 .collect() // Collect all lines into a Vec<Vec<String>>
46 }
47 ```
48
49 Note that using `impl Trait` as an argument type means that you cannot explicitly state what form of the function you use, i.e. `parse_csv_document::<std::io::Empty>(std::io::empty())` will not work with the second example.
50
51
52 ## As a return type
53
54 If your function returns a type that implements `MyTrait`, you can write its
55 return type as `-> impl MyTrait`. This can help simplify your type signatures quite a lot!
56
57 ```rust,editable
58 use std::iter;
59 use std::vec::IntoIter;
60
61 // This function combines two `Vec<i32>` and returns an iterator over it.
62 // Look how complicated its return type is!
63 fn combine_vecs_explicit_return_type(
64 v: Vec<i32>,
65 u: Vec<i32>,
66 ) -> iter::Cycle<iter::Chain<IntoIter<i32>, IntoIter<i32>>> {
67 v.into_iter().chain(u.into_iter()).cycle()
68 }
69
70 // This is the exact same function, but its return type uses `impl Trait`.
71 // Look how much simpler it is!
72 fn combine_vecs(
73 v: Vec<i32>,
74 u: Vec<i32>,
75 ) -> impl Iterator<Item=i32> {
76 v.into_iter().chain(u.into_iter()).cycle()
77 }
78
79 fn main() {
80 let v1 = vec![1, 2, 3];
81 let v2 = vec![4, 5];
82 let mut v3 = combine_vecs(v1, v2);
83 assert_eq!(Some(1), v3.next());
84 assert_eq!(Some(2), v3.next());
85 assert_eq!(Some(3), v3.next());
86 assert_eq!(Some(4), v3.next());
87 assert_eq!(Some(5), v3.next());
88 println!("all done");
89 }
90 ```
91
92 More importantly, some Rust types can't be written out. For example, every
93 closure has its own unnamed concrete type. Before `impl Trait` syntax, you had
94 to allocate on the heap in order to return a closure. But now you can do it all
95 statically, like this:
96
97 ```rust,editable
98 // Returns a function that adds `y` to its input
99 fn make_adder_function(y: i32) -> impl Fn(i32) -> i32 {
100 let closure = move |x: i32| { x + y };
101 closure
102 }
103
104 fn main() {
105 let plus_one = make_adder_function(1);
106 assert_eq!(plus_one(2), 3);
107 }
108 ```
109
110 You can also use `impl Trait` to return an iterator that uses `map` or `filter`
111 closures! This makes using `map` and `filter` easier. Because closure types don't
112 have names, you can't write out an explicit return type if your function returns
113 iterators with closures. But with `impl Trait` you can do this easily:
114
115 ```rust,editable
116 fn double_positives<'a>(numbers: &'a Vec<i32>) -> impl Iterator<Item = i32> + 'a {
117 numbers
118 .iter()
119 .filter(|x| x > &&0)
120 .map(|x| x * 2)
121 }
122
123 fn main() {
124 let singles = vec![-3, -2, 2, 3];
125 let doubles = double_positives(&singles);
126 assert_eq!(doubles.collect::<Vec<i32>>(), vec![4, 6]);
127 }
128 ```