Замыкания довольно гибкие и делают всё, что требуется для работы с ними без дополнительных указаний. Это позволяет захватывать переменные перемещая их или заимствуя, в зависимости от необходимости. Замыкания могут захватывать переменные:
• по ссылке: &T
• по изменяемой ссылке: &mut T
• по значению: T
Преимущественно, они захватывают переменные по ссылке, если явно не указан другой способ.
fn main() {
use std::mem;
let color = "green";
// Замыкание для вывода `color`, которое немедленно заимствует (`&`)
// `color` и сохраняет замыкание в переменной `print`. color` будет оставаться
// заимствованным до тех пор, пока `print` используется.
//
// `println!` принимает аргументы по неизменяемым ссылкам, поэтому он не накладывает
// дополнительных ограничений.
let print = || println!("`color`: {}", color);
// Вызываем замыкание, использующее заимствование.
print();
// `color` может быть неизменяемо заимствован, так как замыкание
// держит только неизменяемую ссылку на `color`.
let _reborrow = &color;
print();
// Перемещение или перезанятие возможно после последнего использования `print`
let _color_moved = color;
let mut count = 0;
// Замыкание для увеличения `count` может принимать как `&mut count`, так и `count`,
// но использование `&mut count` менее ограничено, так что
// замыкание выбирает первый способ, т.е. немедленно заимствует `count`.
//
// inc` должен быть `mut`, поскольку внутри него хранится `&mut`.
// Таким образом, вызов замыкания изменяет его, что недопустимо без `mut`.
let mut inc = || {
count += 1;
println!("`count`: {}", count);
};
// Вызываем замыкание, использующее изменяемое заимствование.
inc();
// Замыкание продолжает изменяемо заимствовать `count` так как оно используется дальше.
// Попытка перезанять приведёт к ошибке.
// let _reborrow = &count;
// ^ TODO: попробуйте раскомментировать эту строку.
inc();
// Замыкание больше не заимствует `&mut count`. Так что теперь
// при перезаимствовании ошибок не будет.
let _count_reborrowed = &mut count;
// Некопируемый тип.
let movable = Box::new(3);
// `mem::drop` требует `T`, так что захват производится по значению.
// Копируемый тип будет скопирован в замыкание, оставив оригинальное
// значение без изменения. Некопируемый тип должен быть перемещён, так что
// movable` немедленно перемещается в замыкание.
let consume = || {
println!("`movable`: {:?}", movable);
mem::drop(movable);
};
// `consume` поглощает переменную, так что оно может быть вызвано только один раз.
consume();
// consume();
// ^ TODO: Попробуйте раскомментировать эту строку.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Использование move перед вертикальными линиями позволяет получить владение над захваченными переменными:
fn main() {
// Vec` не поддерживает копирование.
let haystack = vec![1, 2, 3];
let contains = move |needle| haystack.contains(needle);
println!("{}", contains(&1));
println!("{}", contains(&4));
// println!("Количество элементов {} в векторе", haystack.len());
// ^ Уберите комментарий с этой строки и в результате получите ошибку компиляции,
// потому что анализатор заимствований не позволяет использовать
// переменную после передачи владения.
// Удалите `move` у замыкания и _haystack_ будет заимствован по неизменяемой
// ссылке, и удалённый комментарий теперь не вызывает ошибки.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Box и std::mem::drop