DEV Community

Cover image for [Rust Guide] 13.7. Using Closures to Capture the Environment With Iterators
SomeB1oody
SomeB1oody

Posted on

[Rust Guide] 13.7. Using Closures to Capture the Environment With Iterators

13.7.0 Before We Begin

During its design, Rust drew inspiration from many languages, and functional programming had a particularly strong influence on Rust. Functional programming often includes passing functions as values to parameters, returning them from other functions, assigning them to variables for later execution, and so on.

In this chapter, we will discuss some Rust features that are similar to what many languages call functional features:

  • Closures
  • Iterators (this article)
  • Improving the I/O Project with Closures and Iterators
  • Performance of Closures and Iterators

If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.

13.7.1 Using Closures to Capture the Environment

The filter method is an iterator adaptor that is usually used together with a closure that captures the environment.

The filter method takes a closure that returns a boolean value as it traverses each element of the iterator. If the return value is true, the current element will be included in the new iterator produced by filter; otherwise, the current element will not be included.

Take an example:

Use filter with a closure to capture the shoe_size variable from the environment and iterate over a collection of Shoe struct instances. It will return only shoes of the specified size.

#[derive(PartialEq, Debug)]
struct Shoe {
    size: u32,
    style: String,
}

fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
    shoes.into_iter().filter(|s| s.size == shoe_size).collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn filters_by_size() {
        let shoes = vec![
            Shoe {
                size: 10,
                style: String::from("sneaker"),
            },
            Shoe {
                size: 13,
                style: String::from("sandal"),
            },
            Shoe {
                size: 10,
                style: String::from("boot"),
            },
        ];

        let in_my_size = shoes_in_size(shoes, 10);

        assert_eq!(
            in_my_size,
            vec![
                Shoe {
                    size: 10,
                    style: String::from("sneaker")
                },
                Shoe {
                    size: 10,
                    style: String::from("boot")
                },
            ]
        );
    }
}
Enter fullscreen mode Exit fullscreen mode
  • The Shoe struct has two fields: size, which represents the shoe size and is of type u32, and style, which represents the style and is of type String.

  • The shoes_in_size function takes two parameters: shoes, whose type is Vec<Shoe>, and shoe_size, whose type is u32, and it returns a Vec<Shoe>. The function body first calls into_iter on the incoming Vector to create an iterator that takes ownership. Then it uses filter, whose argument is a closure. The closure checks each element’s size field to see whether it matches shoe_size; if it does, the element is included in the new iterator. Finally, collect is called to turn the result into a collection and return it.

Top comments (0)