Chaining methods
Rust is a systems programming language like C and C++, and its code can be written as separate commands in separate lines, but it also has a functional style. Both styles are okay, but functional style is usually shorter. Here is an example of the non-functional style (called "imperative style") to make a Vec
from 1 to 10:
fn main() { let mut new_vec = Vec::new(); let mut counter = 1; while counter < 11 { new_vec.push(counter); counter += 1; } println!("{:?}", new_vec); }
This prints [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.
And here is an example of functional style:
fn main() { let new_vec = (1..=10).collect::<Vec<i32>>(); // Or you can write it like this: // let new_vec: Vec<i32> = (1..=10).collect(); println!("{:?}", new_vec); }
.collect()
can make collections of many types, so we have to tell it the type.
With functional style you can chain methods. "Chaining methods" means to put many methods together in a single statement. Here is an example of many methods chained together:
fn main() { let my_vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let new_vec = my_vec.into_iter().skip(3).take(4).collect::<Vec<i32>>(); println!("{:?}", new_vec); }
This creates a Vec with [3, 4, 5, 6]
. This is a lot of information for one line, so it can help to put each method on a new line. Let's do that to make it easier to read:
fn main() { let my_vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let new_vec = my_vec .into_iter() // "iterate" over the items (iterate = work with each item inside it). into_iter() gives us owned values, not references .skip(3) // skip over three items: 0, 1, and 2 .take(4) // take the next four: 3, 4, 5, and 6 .collect::<Vec<i32>>(); // put them in a new Vec<i32> println!("{:?}", new_vec); }
You can use this functional style best when you understand closures and iterators. So we will learn them next.