Замыкания
Замыкания в Rust - это анонимные функции, которые можно сохранять в переменных или передавать в качестве аргументов другим функциям. Вы можете создать замыкание в одном месте, а затем вызвать его в каком-нибудь другом, чтобы выполнить обработку в ином контексте. В отличие от функций, замыкания могут использовать значения из области видимости в которой они были определены.
Хорошая функция unwrap_or_else(|| self.most_stocked())
Очень любит замыкания!
Если значение на входе не содержит Some, то выполнит замыкание в скобках.
|| self.most_stocked():
||— между этими полосами передаем параметры в замыканиеself.most_stocked()— собственно сама функция замыкания
Замыкания обычно не требуют аннотирования типов входных параметров или возвращаемого значения, как это делается в функциях fn
Если нужно добавить аннотацию, то выглядит так:
#![allow(unused)] fn main() { let expensive_closure = |num: u32| -> u32 { println!("calculating slowly..."); thread::sleep(Duration::from_secs(2)); num }; }
или так
#![allow(unused)] fn main() { 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 ; }
это замыкание
#![allow(unused)] fn main() { let clos1 = |x,y| for _ in 1..=y {print!("{x}")}; clos1("=",20); }
Замыкание самостоятельно определяет, какой из этих способов владения использовать, исходя из того, что тело функции делает с полученными значениями.
Ссылка на входе (не изменяемое)
#![allow(unused)] fn main() { let list = vec![1, 2, 3]; println!("Before defining closure: {list:?}"); let only_borrows = || println!("From closure: {list:?}"); println!("Before calling closure: {list:?}"); only_borrows(); println!("After calling closure: {list:?}"); }
Изменение значения
#![allow(unused)] fn main() { let mut list = vec![1, 2, 3]; println!("Before defining closure: {list:?}"); let mut only_borrows = || list.push(7); only_borrows(); println!("After calling closure: {list:?}"); }
Порождение нового потока (move)
use std::thread; fn main() { let list = vec![1, 2, 3]; println!("Before defining closure: {list:?}"); thread::spawn(move || println!("From thread: {list:?}")) .join() .unwrap(); }
Перемещение захваченных значений из замыканий
Тело замыкания может делать любое из следующих действий: перемещать захваченное значение из замыкания, изменять захваченное значение, не перемещать и не изменять значение или вообще ничего не захватывать из среды.
Трейты замыканий
FnOnceприменяется к замыканиям, которые могут быть вызваны один раз.
Замыкание, которое перемещает захваченные значения из своего тела, реализует только
FnOnce
#![allow(unused)] fn main() { impl<T> Option<T> { pub fn unwrap_or_else<F>(self, f: F) -> T where F: FnOnce() -> T //будет вызвано только один раз { match self { Some(x) => x, None => f(), } } } }
FnMutприменяется к замыканиям, которые не перемещают захваченные значения из своего тела, но могут изменять захваченные значения.
#![allow(unused)] fn main() { list2.sort_by_key(|r| r.width); println!("{list2:#?}"); }
Fnприменяется к замыканиям, которые не перемещают захваченные значения из своего тела и не модифицируют захваченные значения, а также к замыканиям, которые ничего не захватывают из своего окружения.