-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
222 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
content/lessons/06_closures_iterators/closures_capturing.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
fn main() { | ||
borrowing_immutably_closure(); | ||
borrowing_mutably_closure(); | ||
moving_in_nonmutating_closure(); | ||
moving_in_mutating_closure(); | ||
moving_in_moving_out_closure(); | ||
} | ||
|
||
fn borrowing_immutably_closure() { | ||
let list = vec![1, 2, 3]; | ||
println!("Before defining closure: {:?}", list); | ||
|
||
let only_borrows = || println!("From closure: {:?}", list); | ||
|
||
// This would not really only borrow... (it needs Vec by value). | ||
// let only_borrows = || std::mem::drop::<Vec<_>>(list); | ||
|
||
println!("Before calling closure: {:?}", list); | ||
only_borrows(); | ||
println!("After calling closure: {:?}", list); | ||
} | ||
|
||
fn borrowing_mutably_closure() { | ||
let mut list = vec![1, 2, 3]; | ||
println!("Before defining closure: {:?}", list); | ||
|
||
let mut borrows_mutably = || list.push(7); | ||
|
||
// println!("Before calling closure: {:?}", list); | ||
borrows_mutably(); | ||
println!("After calling closure: {:?}", list); | ||
} | ||
|
||
fn moving_in_nonmutating_closure() { | ||
let list = vec![1, 2, 3]; | ||
println!("Before defining closure: {:?}", list); | ||
|
||
// This closure would just borrow the list, because it only prints it. | ||
// However, as spawning threads require passing `impl FnOnce + 'static`, | ||
// we need to use `move` keyword to force the closure to move `list` | ||
// into its captured environment. | ||
std::thread::spawn(move || println!("From thread: {:?}", list)) | ||
.join() | ||
.unwrap(); | ||
} | ||
|
||
fn moving_in_mutating_closure() { | ||
fn append_42(mut appender: impl FnMut(i32)) { | ||
appender(42); | ||
} | ||
|
||
let mut appender = { | ||
let mut list = vec![1, 2, 3]; | ||
println!("Before defining closure: {:?}", list); | ||
|
||
// The `move` keyword is necessary to prevent dangling reference to `list`. | ||
// Of course, the borrow checker protects us from compiling code without `move`. | ||
move |num| list.push(num) | ||
}; | ||
|
||
append_42(&mut appender); | ||
append_42(&mut appender); | ||
} | ||
|
||
fn moving_in_moving_out_closure() { | ||
fn append_multiple_times(appender: impl FnOnce(&mut Vec<String>) + Clone) { | ||
let mut list = Vec::new(); | ||
|
||
// We can clone this `FnOnce`, because we additionally require `Clone`. | ||
// If we didn't clone it, we couldn't call it more than *once*. | ||
appender.clone()(&mut list); | ||
appender(&mut list); | ||
} | ||
|
||
let appender = { | ||
let string = String::from("Ala"); | ||
println!("Before defining closure: {:?}", string); | ||
|
||
// The `move` keyword is necessary to prevent dangling reference to `list`. | ||
// Of course, the borrow checker protects us from compiling code without `move`. | ||
move |list: &mut Vec<String>| list.push(string) | ||
}; | ||
|
||
// As `appender` is only `FnOnce`, we need to clone before we consume it by calling it. | ||
append_multiple_times(appender.clone()); | ||
append_multiple_times(appender); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
fn main() { | ||
fn some_function() -> String { | ||
String::new() | ||
} | ||
|
||
let v1 = String::from("v1"); | ||
let mut borrowing_immutably_closure = || v1.clone(); | ||
|
||
let mut v2 = String::from("v2"); | ||
let mut borrowing_mutably_closure = || { | ||
v2.push('.'); | ||
v2.clone() | ||
}; | ||
|
||
let v3 = String::from("v3"); | ||
let mut moving_in_nonmutating_closure = move || v3.clone(); | ||
|
||
let mut v4 = String::from("v4"); | ||
let mut moving_in_mutating_closure = move || { | ||
v4.push('.'); | ||
v4.clone() | ||
}; | ||
let v5 = String::from("v5"); | ||
let moving_in_moving_out_closure = || v5; | ||
|
||
let fn_once_callables: [&dyn FnOnce() -> String; 5] = [ | ||
&some_function, | ||
&borrowing_immutably_closure, | ||
&borrowing_mutably_closure, | ||
&moving_in_nonmutating_closure, | ||
&moving_in_moving_out_closure, | ||
]; | ||
|
||
#[allow(unused_variables)] | ||
for fn_once_callable in fn_once_callables { | ||
// Cannot move a value of type `dyn FnOnce() -> String`. | ||
// The size of `dyn FnOnce() -> String` cannot be statically determined. | ||
// println!("{}", fn_once_callable()); | ||
|
||
// So, for FnOnce, we need to be their owners to be able to call them, | ||
// and we can't have a `dyn` object owned on stack. | ||
// We will solve this problem soon with smart pointers (e.g., Box). | ||
} | ||
|
||
// Mutable reference to FnMut is required to be able to call it. | ||
let fn_mut_callables: [&mut dyn FnMut() -> String; 4] = [ | ||
&mut borrowing_immutably_closure, | ||
&mut borrowing_mutably_closure, | ||
&mut moving_in_nonmutating_closure, | ||
&mut moving_in_mutating_closure, | ||
]; | ||
|
||
for fn_mut_callable in fn_mut_callables { | ||
println!("{}", fn_mut_callable()); | ||
} | ||
|
||
let fn_callables: &[&dyn Fn() -> String] = | ||
&[&borrowing_immutably_closure, &moving_in_nonmutating_closure]; | ||
|
||
for fn_callable in fn_callables { | ||
println!("{}", fn_callable()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
fn main() { | ||
#[rustfmt::skip] | ||
{ | ||
// This is formatted so that with rust-analyzer it renders as well-aligned. | ||
|
||
fn add_one_v1 (x: u32) -> u32 { x + 1 } // This is an ordinary function. | ||
let add_one_v2 = |x: u32| -> u32 { x + 1 }; // Closures use pipes instead of parentheses. | ||
let add_one_v3 = |x| { x + 1 }; // Both parameters and return value can have their types inferred. | ||
let add_one_v4 = |x| x + 1 ; // If the body is a single expression, braces can be omitted. | ||
|
||
let _res = add_one_v1(0_u32); | ||
let _res = add_one_v2(0_u32); | ||
let _res = add_one_v3(0_u32); | ||
let _res = add_one_v4(0_u32); | ||
|
||
// This does not compile, because closures are not generic. | ||
// Their type is inferred once and stays the same. | ||
// let _res = add_one_v4(0_i32); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters