almost done w/ ch13.01
This commit is contained in:
parent
83d8d2245c
commit
6010b12653
7
ch13/closures/Cargo.lock
generated
Normal file
7
ch13/closures/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "closures"
|
||||
version = "0.1.0"
|
6
ch13/closures/Cargo.toml
Normal file
6
ch13/closures/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "closures"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
14
ch13/closures/src/lib.rs
Normal file
14
ch13/closures/src/lib.rs
Normal file
@ -0,0 +1,14 @@
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
192
ch13/closures/src/main.rs
Normal file
192
ch13/closures/src/main.rs
Normal file
@ -0,0 +1,192 @@
|
||||
// Closures are anonymous functions. Can save in variables or pass
|
||||
// to other functions. Closures can capture the values from the scope
|
||||
// they're defined in.
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
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
|
||||
);
|
||||
|
||||
// closure type inference and annotation
|
||||
let expensive_closure = |num: u32| -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
num
|
||||
};
|
||||
|
||||
// similarity between closures and functions
|
||||
fn add_one_v1(x: u32) -> u32 {
|
||||
x + 1
|
||||
}
|
||||
let add_one_v2 = |x: u32| -> u32 { x + 1 };
|
||||
|
||||
// capturing references or moving ownership
|
||||
// closures capture values from env in 3 ways
|
||||
// 1) borrowing immutably
|
||||
// 2) borrowing mutably
|
||||
// 3) taking ownership
|
||||
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:?}");
|
||||
|
||||
// change closure body to push instead of print
|
||||
let mut list = vec![1, 2, 3, 4];
|
||||
println!("Before defining closure: {list:?}");
|
||||
|
||||
let mut borrows_mutably = || list.push(7);
|
||||
|
||||
// println!("Before calling closure: {list:?}");
|
||||
borrows_mutably();
|
||||
println!("After calling closure: {list:?}");
|
||||
|
||||
// If want to force closure to take ownership of values it uses even
|
||||
// tho closure doesn't strictly need ownership, use the `move` keyword
|
||||
let list = vec![1, 2, 3];
|
||||
println!("Before defining closure: {list:?}");
|
||||
|
||||
thread::spawn(move || println!("From thread: {list:?}"))
|
||||
.join()
|
||||
.unwrap();
|
||||
|
||||
// Moving captured values out of the closures and the Fn traits
|
||||
// Once a closure has captured a reference or captured ownership of a value
|
||||
// from the env where closure is defined (affecting what is moved into the
|
||||
// closure), the code in the body of the closure defines what happens to
|
||||
// the references or values when the closure is evaluated later (affecting
|
||||
// what is moved out of the closure). Closure body can do any of the following:
|
||||
// 1) move captured value out of the closure
|
||||
// 2) mutate captured value
|
||||
// 3) neither move nor mutate the value
|
||||
// 4) capture nothing from the env to begin with
|
||||
//
|
||||
// Closures will automatically implement some or all of the following
|
||||
// traits in an additive fashing depending on the closure's body
|
||||
// handles the values
|
||||
// 1) FnOnce applies to all closures that can be called once.
|
||||
// All closures implement at least this trait. A closure that
|
||||
// moves captured values out of its body will only implement
|
||||
// FnOnce and one of the other Fn traits, because it can only
|
||||
// by called once.
|
||||
// 2) FnMut applies to closures that don't move captured values out
|
||||
// of their body but might mutate the captured values. These
|
||||
// closures can't be called more than once.
|
||||
// 3) Fn applies to closures that don't move captured values out of
|
||||
// their body and that don't mutate captured values, and closures
|
||||
// that capture nothing from their environment. These closures can
|
||||
// be called more than once without mutating their environment. This
|
||||
// is nice for calling a closure multiple times concurrently.
|
||||
|
||||
// sort_by_key uses FnMut
|
||||
let mut list = [
|
||||
Rectangle {
|
||||
width: 10,
|
||||
height: 1,
|
||||
},
|
||||
Rectangle {
|
||||
width: 3,
|
||||
height: 5,
|
||||
},
|
||||
Rectangle {
|
||||
width: 7,
|
||||
height: 12,
|
||||
},
|
||||
];
|
||||
|
||||
// let mut sort_operations = vec![];
|
||||
// let value = String::from("closure called");
|
||||
let mut num_sort_operations = 0;
|
||||
|
||||
// list.sort_by_key(|r| r.width);
|
||||
list.sort_by_key(|r| {
|
||||
// sort_operations.push(value);
|
||||
num_sort_operations += 1;
|
||||
r.width
|
||||
});
|
||||
println!("{list:#?}");
|
||||
|
||||
// closures must name captured lifetimes
|
||||
|
||||
// Stopped here:
|
||||
// https://rust-book.cs.brown.edu/ch13-01-closures.html#closures-must-name-captured-lifetimes
|
||||
}
|
||||
|
||||
// from closures must name captured lifetimes
|
||||
fn make_a_cloner(s_ref: &str) -> impl Fn() -> String {
|
||||
move || s_ref.to_string()
|
||||
}
|
||||
|
||||
// The implementation for unwrap_or_else
|
||||
// Uses FnOnce
|
||||
// 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(),
|
||||
// }
|
||||
// }
|
||||
// }
|
Loading…
x
Reference in New Issue
Block a user