Выражения замыканий
Syntax
ClosureExpression →
async?1
move?
( || | | ClosureParameters? | )
( Expression | -> TypeNoBounds BlockExpression )
ClosureParameters → ClosureParam ( , ClosureParam )* ,?
ClosureParam → OuterAttribute* PatternNoTopAlt ( : Type )?
Выражение замыкания, также известное как лямбда-выражение или лямбда, определяет тип замыкания и вычисляется в значение этого типа.
Синтаксис выражения замыкания: необязательное ключевое слово async, необязательное ключевое слово move, затем разделенный символами трубы (|) список образцов, называемый параметрами замыкания, каждый из которых необязательно сопровождается : и типом, затем необязательный -> и тип, называемый типом возврата, и затем выражение, называемое операндом тела замыкания.
Необязательный тип после каждого образца является аннотацией типа для образца.
Если указан тип возврата, тело замыкания должно быть блоком.
Выражение замыкания обозначает функцию, которая отображает список параметров на выражение, следующее за параметрами.
Так же, как привязка let, параметры замыкания являются неопровержимыми образцами, чья аннотация типа необязательна и будет выведена из контекста, если не указана.
Каждое выражение замыкания имеет уникальный, анонимный тип.
Существенно, что выражения замыкания захватывают свое окружение, чего обычные определения функций не делают.
Без ключевого слова move выражение замыкания выводит, как оно захватывает каждую переменную из своего окружения, предпочитая захват по разделяемой ссылке, эффективно заимствуя все внешние переменные, упомянутые внутри тела замыкания.
При необходимости компилятор выведет, что вместо этого должны быть взяты изменяемые ссылки, или что значения должны быть перемещены или скопированы (в зависимости от их типа) из окружения.
Замыкание можно принудительно заставить захватывать свое окружение путем копирования или перемещения значений, добавив перед ним ключевое слово move.
Это часто используется для обеспечения того, чтобы время жизни замыкания было 'static.
Реализации трейтов замыкания
Какие трейты реализует тип замыкания, зависит от того, как захватываются переменные, типов захваченных переменных и наличия async.
Смотрите главу трейты вызова и приведения для информации о том, как и когда замыкание реализует Fn, FnMut и FnOnce.
Тип замыкания реализует Send и Sync, если тип каждой захваченной переменной также реализует этот трейт.
Асинхронные замыкания
Замыкания, помеченные ключевым словом async, указывают, что они являются асинхронными, аналогично асинхронной функции.
Вызов асинхронного замыкания не выполняет никакой работы, но вместо этого вычисляется в значение, которое реализует Future и соответствует вычислению тела замыкания.
#![allow(unused)] fn main() { async fn takes_async_callback(f: impl AsyncFn(u64)) { f(0).await; f(1).await; } async fn example() { takes_async_callback(async |i| { core::future::ready(i).await; println!("done with {i}."); }).await; } }
2018 Edition differences
Асинхронные замыкания доступны только начиная с Rust 2018.
Пример
В этом примере мы определяем функцию ten_times, которая принимает аргумент функции высшего порядка, а затем вызываем ее с выражением замыкания в качестве аргумента, за которым следует выражение замыкания, которое перемещает значения из своего окружения.
#![allow(unused)] fn main() { fn ten_times<F>(f: F) where F: Fn(i32) { for index in 0..10 { f(index); } } ten_times(|j| println!("hello, {}", j)); // С аннотациями типов ten_times(|j: i32| -> () { println!("hello, {}", j) }); let word = "konnichiwa".to_owned(); ten_times(move |j| println!("{}, {}", word, j)); }
Атрибуты на параметрах замыкания
Атрибуты на параметрах замыкания следуют тем же правилам и ограничениям, что и обычные параметры функции.
-
Квалификатор
asyncне разрешен в редакции 2015. ↩