Chapter 14. Closures

Save the environment! Create a closure today!

Cormac Flanagan

Sorting a vector of integers is easy:

integers.sort();

It is, therefore, a sad fact that when we want some data sorted, it’s hardly ever a vector of integers. We typically have records of some kind, and the built-in sort method typically does not work:

struct City {
    name: String,
    population: i64,
    country: String,
    ...
}

fn sort_cities(cities: &mut Vec<City>) {
    cities.sort();  // error: how do you want them sorted?
}

Rust complains that City does not implement std::cmp::Ord. We need to specify the sort order, like this:

/// Helper function for sorting cities by population.
fn city_population_descending(city: &City) -> i64 {
    -city.population
}

fn sort_cities(cities: &mut Vec<City>) {
    cities.sort_by_key(city_population_descending);  // ok
}

The helper function, city_population_descending, takes a City record and extracts the key, the field by which we want to sort our data. (It returns a negative number because sort arranges numbers in increasing order, and we want decreasing order: the most populous city first.) The sort_by_key method takes this key-function as a parameter.

This works fine, but it’s more concise to write the helper function as a closure, an anonymous function expression:

fn sort_cities(cities: &mut Vec<City>) {
    cities.sort_by_key(|city| -city.population);
}

The closure here is |city| -city.population. It takes an argument city and returns -city.population. Rust infers ...

Get Programming Rust, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.