use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Map;
use std::thread;
use std::time::Duration;
#[derive(Debug, PartialEq, Copy, Clone)]
enum ShirtColor {
Red,
Blue,
}
struct Inventory {
shirts: Vec<ShirtColor>,
}
impl Inventory {
fn giveaway(&self, user_preference: Option<ShirtColor>) -> ShirtColor {
user_preference.unwrap_or_else(|| self.most_stocked())
}
fn most_stocked(&self) -> ShirtColor {
let mut num_red = 0;
let mut num_blue = 0;
for color in &self.shirts {
match color {
ShirtColor::Red => num_red += 1,
ShirtColor::Blue => num_blue += 1,
}
}
if num_red > num_blue {
ShirtColor::Red
} else {
ShirtColor::Blue
}
}
}
pub fn closure_demo() {
let store = Inventory {
shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue],
};
let user_pref1 = Some(ShirtColor::Red);
let giveaway1 = store.giveaway(user_pref1);
println!(
"The user with preference {:?} gets {:?}",
user_pref1, giveaway1
);
let user_pref2 = None;
let giveaway2 = store.giveaway(user_pref2);
println!(
"The user with preference {:?} gets {:?}",
user_pref2, giveaway2
);
}
pub(crate) fn closure_var() {
let expensive_closure = |num: u32| -> u32 {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
};
fn add_one_v1(x: u32) -> u32 {
x + 1
}
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let example_closure = |x| x;
let s = example_closure(String::from("hello"));
}
pub fn closure_ownership() {
closure_borrow();
closure_borrow_mut();
closure_move_owner();
}
fn closure_move_owner() {
let list = vec![1, 2, 3];
println!("Before defining closure: {:?}", list);
thread::spawn(move || println!("From thread: {:?}", list))
.join()
.unwrap();
}
fn closure_borrow_mut() {
let mut list = vec![1, 2, 3];
println!("Before defining closure: {:?}", list);
let mut borrows_mutably = || list.push(7);
borrows_mutably();
println!("After calling closure: {:?}", list);
}
fn closure_borrow() {
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);
}
#[derive(Debug)]
pub struct Rectangle {
pub width: u32,
pub height: u32,
}
pub(crate) fn closure_fn() {
let mut list = [
Rectangle {
width: 10,
height: 1,
},
Rectangle {
width: 3,
height: 5,
},
Rectangle {
width: 7,
height: 12,
},
];
list.sort_by_key(|r| r.width);
println!("{:#?}", list);
let mut sort_operations = vec![];
let value = String::from("by key called");
let count = 1;
list.sort_by_key(|r| {
sort_operations.push(&value); r.width
});
println!("{:#?}", sort_operations);
let mut num_sort_operations = 0;
list.sort_by_key(|r| {
num_sort_operations += 1;
r.width
});
println!("{:#?}, sorted in {num_sort_operations} operations", list); }
pub fn closure() {
let simulated_user_specified_value = 10;
let simulated_random_number = 7;
generate_workout(simulated_user_specified_value, simulated_random_number);
}
struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}
fn generate_workout(intensity: u32, random_number: u32) {
let mut expensive_closure = Cacher::new(|num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
});
if intensity < 25 {
println!(
"Today, do {:?} pushups!",
expensive_closure.value(intensity)
);
println!("Next, do {:?} situps!", expensive_closure.value(intensity));
} else if random_number == 3 {
println!("Take a break today! Remember to stay hydrated!");
} else {
println!(
"Today, run for {:?} minutes!",
expensive_closure.value(intensity)
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore]
fn call_with_different_values() {
let mut c = Cacher::new(|a| a);
let v1 = c.value(1);
let v2 = c.value(2);
assert_eq!(v2, 1);
}
}
pub fn closure_scope() {
let x = 4;
let equal_to_x = |z| z == x;
let y = 4;
assert!(equal_to_x(y));
}
pub fn closure_move() {
let x = vec![1, 2, 3];
let equal_to_x = move |z| z == x;
let y = vec![1, 2, 3];
assert!(equal_to_x(y));
}