Rust tiene algo que se denomina closure o cierre, son valores ligeramente similar a las funciones. Un closure generalmente consiste en una lista de argumentos, dada entre barras verticales, seguida de una expresión.

Rust infiere los tipos de argumentos y el tipo de retorno. También puede escribirlos explícitamente, como lo haría para una función. Si especifica un tipo de retorno, entonces el cuerpo del el cierre debe ser un bloque, en aras de la cordura sintáctica.

fn  add_one_v1   (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x|             { x + 1 };
let add_one_v4 = |x|               x + 1  ;

let example_closure = |x| x;
let s = example_closure(String::from("hello"));
let n = example_closure(5);

let expensive_closure = |num: u32| -> u32 {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
 };

Ordenar un vector de enteros es fácil:

integers.sort()

Por lo tanto, es un hecho triste que cuando queremos ordenar algunos datos, casi nunca es un vector de números enteros. Por lo general, tenemos registros de algunos tipos y el método de clasificación incorporado normalmente no funciona:

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 se queja de que City no implementa std::cmp::Ord. Necesitamos especificar el orden de clasificación, así:

/// Helper function for sorting cities by population.
 fn city_population_descending(city: &City) -> i64 {
		- city.population
 }
 fn sort_cities(cities: &mut Vec<City>) {
// ok
 cities.sort_by_key(city_population_descending);
 }

La función auxiliar, city_population_descending, toma un registro de Ciudad y extrae la clave, el campo por el cual queremos ordenar nuestros datos. (Devuelve un número negativo porque sort organiza los números en orden creciente y queremos un orden decreciente: la ciudad más poblada primero.) El método sort_by_key toma esta función clave como parámetro. Esto funciona bien, pero es más conciso escribir la función auxiliar como un cierre, una expresión de función anónima:

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

El cierre aquí es |city| -city.population. Se necesita una city como argumento y devuelve -city.population. Rust infiere el tipo de argumento y el tipo de retorno de cómo se usa el cierre. Otros ejemplos de funciones de biblioteca estándar que aceptan cierres incluyen:

Por supuesto, las funciones anónimas están en todas partes en estos días, incluso en lenguajes como Java, C#, Python y C++ que originalmente no las tenían. A partir de ahora, asumiremos que ha visto funciones anónimas antes y nos centraremos en lo que hace que los cierres de Rust sean un poco diferentes. En este capítulo, aprenderá los tres tipos de Cierres:

  1. cómo un closure puede "capturar" variables en su alcance. (Borrow/Ownership)
  2. cómo usar closure con métodos de biblioteca estándar.
  3. cómo escribir sus propias funciones y métodos que toman las clausuras como argumentos.