From 2b5e7cba88607a23740d5bf1e5c93e7317a88179 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 5 Dec 2024 11:14:48 +0000 Subject: [PATCH] Deploy mimuw-jnp2-rust/mimuw-jnp2-rust.github.io to mimuw-jnp2-rust/mimuw-jnp2-rust.github.io:gh-pages --- 404.html | 3 + atom.xml | 9224 +++++++++++++++++ book.css | 1 + book.js | 232 + elasticlunr.min.js | 10 + index.html | 239 + lessons/00-organizational/index.html | 257 + .../A_taste_of_Rust.html | 4780 +++++++++ .../A_taste_of_Rust.pdf | Bin 0 -> 52282 bytes lessons/01-introduction/clippy.jpg | Bin 0 -> 27148 bytes lessons/01-introduction/conditionals.rs | 20 + lessons/01-introduction/cpp_meme.jpg | Bin 0 -> 128164 bytes lessons/01-introduction/errors_demo.c | 35 + lessons/01-introduction/errors_demo.cpp | 49 + lessons/01-introduction/errors_demo.rs | 29 + lessons/01-introduction/functions.rs | 12 + lessons/01-introduction/hello_world.rs | 4 + lessons/01-introduction/index.html | 672 ++ lessons/01-introduction/loops.rs | 55 + lessons/01-introduction/students/gasinska.py | 107 + lessons/01-introduction/students/grodzicki.py | 7 + lessons/01-introduction/students/koszowski.go | 88 + lessons/01-introduction/students/tudruj.cpp | 28 + lessons/01-introduction/variables.rs | 18 + .../a-taste-of-rust/index.html | 43 + .../aliasing-xor-mutability/Cargo.toml | 4 + .../aliasing-xor-mutability/src/main.rs | 39 + .../02-ownership/dont_panic/dont_panic.html | 3903 +++++++ .../02-ownership/dont_panic/dont_panic.pdf | Bin 0 -> 45178 bytes lessons/02-ownership/index.html | 515 + .../string_formatting/string_formatting.html | 3842 +++++++ .../string_formatting/string_formatting.pdf | Bin 0 -> 33439 bytes .../dont_panic/dont-panic/index.html | 43 + .../string-formatting/index.html | 43 + lessons/03-data-types/data_types.rs | 88 + lessons/03-data-types/enums.c | 35 + lessons/03-data-types/enums.rs | 28 + lessons/03-data-types/index.html | 797 ++ .../module_system/module_system.html | 253 + .../module_system/module_system.pdf | Bin 0 -> 43577 bytes lessons/03-data-types/option.rs | 112 + lessons/03-data-types/pattern_matching.rs | 128 + lessons/03-data-types/result.rs | 56 + lessons/03-data-types/tagged_union.cpp | 35 + .../module_system/module-system/index.html | 43 + lessons/04-feedback-1/index.html | 301 + lessons/05-types-reasoning/basic_trait.rs | 38 + .../05-types-reasoning/basic_trait_display.rs | 40 + lessons/05-types-reasoning/generic_largest.rs | 23 + lessons/05-types-reasoning/generics.rs | 89 + lessons/05-types-reasoning/generics_fun.rs | 35 + lessons/05-types-reasoning/impl_trait.rs | 73 + lessons/05-types-reasoning/index.html | 1194 +++ lessons/05-types-reasoning/lifetimes_basic.rs | 27 + .../05-types-reasoning/lifetimes_elision.rs | 16 + lessons/05-types-reasoning/non_generic.rs | 35 + .../static_dynamic_dispatch.rs | 47 + .../trait_associated_type.rs | 77 + lessons/05-types-reasoning/trait_default.rs | 67 + .../05-types-reasoning/trait_generic_type.rs | 96 + .../closures_capturing.rs | 87 + lessons/06-closures-iterators/closures_fun.rs | 64 + .../06-closures-iterators/closures_syntax.rs | 20 + lessons/06-closures-iterators/index.html | 536 + .../iterator_exhaustion.rs | 58 + lessons/07-smart-pointers/box.rs | 18 + lessons/07-smart-pointers/deref_coercion.rs | 39 + lessons/07-smart-pointers/index.html | 417 + lessons/07-smart-pointers/ref_count.rs | 31 + lessons/07-smart-pointers/weak_ref.rs | 36 + lessons/08-feedback-2/index.html | 256 + lessons/09-concurrency/index.html | 389 + lessons/10-design-patterns/index.html | 246 + lessons/11-async-1/index.html | 240 + lessons/12-project-feedback/index.html | 396 + lessons/13-async-2/index.html | 388 + lessons/14-macros/index.html | 245 + lessons/index.html | 328 + .../old/2021L/00-organizational/index.html | 43 + lessons/old/2021L/01-introduction/clippy.jpg | Bin 0 -> 27148 bytes .../old/2021L/01-introduction/conditionals.rs | 20 + .../old/2021L/01-introduction/errors_demo.c | 35 + .../old/2021L/01-introduction/errors_demo.cpp | 49 + .../old/2021L/01-introduction/errors_demo.rs | 29 + .../old/2021L/01-introduction/functions.rs | 12 + .../old/2021L/01-introduction/hello_world.rs | 4 + lessons/old/2021L/01-introduction/index.html | 43 + lessons/old/2021L/01-introduction/loops.rs | 55 + .../old/2021L/01-introduction/variables.rs | 18 + lessons/old/2021L/02-ownership/index.html | 43 + lessons/old/2021L/03-data-types/data_types.rs | 82 + lessons/old/2021L/03-data-types/index.html | 43 + lessons/old/2021L/04-enums/enums.c | 29 + lessons/old/2021L/04-enums/enums.rs | 28 + lessons/old/2021L/04-enums/index.html | 43 + lessons/old/2021L/04-enums/option.rs | 112 + .../old/2021L/04-enums/pattern_matching.rs | 128 + lessons/old/2021L/04-enums/result.rs | 56 + lessons/old/2021L/04-enums/tagged_union.cpp | 35 + lessons/old/2021L/05-tests/index.html | 43 + lessons/old/2021L/05-tests/test.rs | 30 + .../2021L/06-types-reasoning/basic_trait.rs | 38 + .../06-types-reasoning/generic_largest.rs | 23 + .../old/2021L/06-types-reasoning/generics.rs | 70 + .../2021L/06-types-reasoning/generics_fun.rs | 35 + .../old/2021L/06-types-reasoning/index.html | 43 + .../06-types-reasoning/lifetimes_basic.rs | 27 + .../06-types-reasoning/lifetimes_elision.rs | 16 + .../2021L/06-types-reasoning/non_generic.rs | 35 + .../static_dynamic_dispatch.rs | 47 + .../2021L/06-types-reasoning/trait_default.rs | 67 + lessons/old/2021L/07-feedback/clippy.png | Bin 0 -> 23592 bytes lessons/old/2021L/07-feedback/constructor.rs | 34 + lessons/old/2021L/07-feedback/index.html | 43 + .../2021L/07-feedback/number_conversions.rs | 9 + lessons/old/2021L/07-feedback/rustfmt.png | Bin 0 -> 18281 bytes .../2021L/08-closures-iterators/index.html | 43 + lessons/old/2021L/09-feedback2/combinators.rs | 37 + lessons/old/2021L/09-feedback2/index.html | 43 + lessons/old/2021L/10-smart-pointers/box.rs | 18 + .../2021L/10-smart-pointers/deref_coercion.rs | 39 + .../old/2021L/10-smart-pointers/index.html | 43 + .../old/2021L/10-smart-pointers/ref_count.rs | 31 + .../old/2021L/10-smart-pointers/weak_ref.rs | 36 + lessons/old/2021L/11-feedback3/index.html | 43 + lessons/old/2021L/12-concurrency/index.html | 43 + .../old/2021L/13-design-patterns/index.html | 43 + lessons/old/2021L/14-async-1/index.html | 43 + lessons/old/2021L/15-async-2/index.html | 43 + lessons/old/2021L/16-macros/index.html | 43 + lessons/old/2021L/b1-rusty-graphs/index.html | 43 + .../old/2022Z/00-organizational/index.html | 43 + lessons/old/2022Z/01-introduction/clippy.jpg | Bin 0 -> 27148 bytes .../old/2022Z/01-introduction/conditionals.rs | 20 + .../old/2022Z/01-introduction/cpp_meme.jpg | Bin 0 -> 128164 bytes .../old/2022Z/01-introduction/errors_demo.c | 35 + .../old/2022Z/01-introduction/errors_demo.cpp | 49 + .../old/2022Z/01-introduction/errors_demo.rs | 29 + .../old/2022Z/01-introduction/functions.rs | 12 + .../old/2022Z/01-introduction/hello_world.rs | 4 + lessons/old/2022Z/01-introduction/index.html | 43 + lessons/old/2022Z/01-introduction/loops.rs | 55 + .../01-introduction/students/gasinska.py | 107 + .../01-introduction/students/grodzicki.py | 7 + .../01-introduction/students/koszowski.go | 88 + .../2022Z/01-introduction/students/tudruj.cpp | 28 + .../old/2022Z/01-introduction/variables.rs | 18 + lessons/old/2022Z/02-ownership/index.html | 43 + lessons/old/2022Z/03-data-types/data_types.rs | 82 + lessons/old/2022Z/03-data-types/enums.c | 29 + lessons/old/2022Z/03-data-types/enums.rs | 28 + lessons/old/2022Z/03-data-types/index.html | 43 + lessons/old/2022Z/03-data-types/option.rs | 112 + .../2022Z/03-data-types/pattern_matching.rs | 128 + lessons/old/2022Z/03-data-types/result.rs | 56 + .../old/2022Z/03-data-types/tagged_union.cpp | 35 + lessons/old/2022Z/04-feedback-1/index.html | 43 + .../2022Z/05-types-reasoning/basic_trait.rs | 38 + .../05-types-reasoning/generic_largest.rs | 23 + .../old/2022Z/05-types-reasoning/generics.rs | 70 + .../2022Z/05-types-reasoning/generics_fun.rs | 35 + .../old/2022Z/05-types-reasoning/index.html | 43 + .../05-types-reasoning/lifetimes_basic.rs | 27 + .../05-types-reasoning/lifetimes_elision.rs | 16 + .../2022Z/05-types-reasoning/non_generic.rs | 35 + .../static_dynamic_dispatch.rs | 47 + .../2022Z/05-types-reasoning/trait_default.rs | 67 + .../2022Z/06-closures-iterators/index.html | 43 + lessons/old/2022Z/07-smart-pointers/box.rs | 18 + .../2022Z/07-smart-pointers/deref_coercion.rs | 39 + .../old/2022Z/07-smart-pointers/index.html | 43 + .../old/2022Z/07-smart-pointers/ref_count.rs | 31 + .../old/2022Z/07-smart-pointers/weak_ref.rs | 36 + lessons/old/2022Z/08-feedback-2/index.html | 43 + lessons/old/2022Z/09-concurrency/index.html | 43 + .../old/2022Z/10-design-patterns/index.html | 43 + lessons/old/2022Z/11-async-1/index.html | 43 + .../old/2022Z/12-project-feedback/index.html | 43 + lessons/project-showcase/fail-menu.png | Bin 0 -> 200400 bytes lessons/project-showcase/game.png | Bin 0 -> 185899 bytes lessons/project-showcase/graph_vis_demo.mkv | Bin 0 -> 8726688 bytes lessons/project-showcase/index.html | 277 + lessons/project-showcase/rusty-dungeon.png | Bin 0 -> 145126 bytes robots.txt | 4 + search_index.en.js | 1 + sitemap.xml | 209 + 186 files changed, 36341 insertions(+) create mode 100644 404.html create mode 100644 atom.xml create mode 100644 book.css create mode 100644 book.js create mode 100644 elasticlunr.min.js create mode 100644 index.html create mode 100644 lessons/00-organizational/index.html create mode 100644 lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.html create mode 100644 lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.pdf create mode 100644 lessons/01-introduction/clippy.jpg create mode 100644 lessons/01-introduction/conditionals.rs create mode 100644 lessons/01-introduction/cpp_meme.jpg create mode 100644 lessons/01-introduction/errors_demo.c create mode 100644 lessons/01-introduction/errors_demo.cpp create mode 100644 lessons/01-introduction/errors_demo.rs create mode 100644 lessons/01-introduction/functions.rs create mode 100644 lessons/01-introduction/hello_world.rs create mode 100644 lessons/01-introduction/index.html create mode 100644 lessons/01-introduction/loops.rs create mode 100644 lessons/01-introduction/students/gasinska.py create mode 100644 lessons/01-introduction/students/grodzicki.py create mode 100644 lessons/01-introduction/students/koszowski.go create mode 100644 lessons/01-introduction/students/tudruj.cpp create mode 100644 lessons/01-introduction/variables.rs create mode 100644 lessons/01_introduction/a_taste_of_rust-introductory_slides/a-taste-of-rust/index.html create mode 100644 lessons/02-ownership/aliasing-xor-mutability/Cargo.toml create mode 100644 lessons/02-ownership/aliasing-xor-mutability/src/main.rs create mode 100644 lessons/02-ownership/dont_panic/dont_panic.html create mode 100644 lessons/02-ownership/dont_panic/dont_panic.pdf create mode 100644 lessons/02-ownership/index.html create mode 100644 lessons/02-ownership/string_formatting/string_formatting.html create mode 100644 lessons/02-ownership/string_formatting/string_formatting.pdf create mode 100644 lessons/02_ownership/dont_panic/dont-panic/index.html create mode 100644 lessons/02_ownership/string_formatting/string-formatting/index.html create mode 100644 lessons/03-data-types/data_types.rs create mode 100644 lessons/03-data-types/enums.c create mode 100644 lessons/03-data-types/enums.rs create mode 100644 lessons/03-data-types/index.html create mode 100644 lessons/03-data-types/module_system/module_system.html create mode 100644 lessons/03-data-types/module_system/module_system.pdf create mode 100644 lessons/03-data-types/option.rs create mode 100644 lessons/03-data-types/pattern_matching.rs create mode 100644 lessons/03-data-types/result.rs create mode 100644 lessons/03-data-types/tagged_union.cpp create mode 100644 lessons/03_data_types/module_system/module-system/index.html create mode 100644 lessons/04-feedback-1/index.html create mode 100644 lessons/05-types-reasoning/basic_trait.rs create mode 100644 lessons/05-types-reasoning/basic_trait_display.rs create mode 100644 lessons/05-types-reasoning/generic_largest.rs create mode 100644 lessons/05-types-reasoning/generics.rs create mode 100644 lessons/05-types-reasoning/generics_fun.rs create mode 100644 lessons/05-types-reasoning/impl_trait.rs create mode 100644 lessons/05-types-reasoning/index.html create mode 100644 lessons/05-types-reasoning/lifetimes_basic.rs create mode 100644 lessons/05-types-reasoning/lifetimes_elision.rs create mode 100644 lessons/05-types-reasoning/non_generic.rs create mode 100644 lessons/05-types-reasoning/static_dynamic_dispatch.rs create mode 100644 lessons/05-types-reasoning/trait_associated_type.rs create mode 100644 lessons/05-types-reasoning/trait_default.rs create mode 100644 lessons/05-types-reasoning/trait_generic_type.rs create mode 100644 lessons/06-closures-iterators/closures_capturing.rs create mode 100644 lessons/06-closures-iterators/closures_fun.rs create mode 100644 lessons/06-closures-iterators/closures_syntax.rs create mode 100644 lessons/06-closures-iterators/index.html create mode 100644 lessons/06-closures-iterators/iterator_exhaustion.rs create mode 100644 lessons/07-smart-pointers/box.rs create mode 100644 lessons/07-smart-pointers/deref_coercion.rs create mode 100644 lessons/07-smart-pointers/index.html create mode 100644 lessons/07-smart-pointers/ref_count.rs create mode 100644 lessons/07-smart-pointers/weak_ref.rs create mode 100644 lessons/08-feedback-2/index.html create mode 100644 lessons/09-concurrency/index.html create mode 100644 lessons/10-design-patterns/index.html create mode 100644 lessons/11-async-1/index.html create mode 100644 lessons/12-project-feedback/index.html create mode 100644 lessons/13-async-2/index.html create mode 100644 lessons/14-macros/index.html create mode 100644 lessons/index.html create mode 100644 lessons/old/2021L/00-organizational/index.html create mode 100644 lessons/old/2021L/01-introduction/clippy.jpg create mode 100644 lessons/old/2021L/01-introduction/conditionals.rs create mode 100644 lessons/old/2021L/01-introduction/errors_demo.c create mode 100644 lessons/old/2021L/01-introduction/errors_demo.cpp create mode 100644 lessons/old/2021L/01-introduction/errors_demo.rs create mode 100644 lessons/old/2021L/01-introduction/functions.rs create mode 100644 lessons/old/2021L/01-introduction/hello_world.rs create mode 100644 lessons/old/2021L/01-introduction/index.html create mode 100644 lessons/old/2021L/01-introduction/loops.rs create mode 100644 lessons/old/2021L/01-introduction/variables.rs create mode 100644 lessons/old/2021L/02-ownership/index.html create mode 100644 lessons/old/2021L/03-data-types/data_types.rs create mode 100644 lessons/old/2021L/03-data-types/index.html create mode 100644 lessons/old/2021L/04-enums/enums.c create mode 100644 lessons/old/2021L/04-enums/enums.rs create mode 100644 lessons/old/2021L/04-enums/index.html create mode 100644 lessons/old/2021L/04-enums/option.rs create mode 100644 lessons/old/2021L/04-enums/pattern_matching.rs create mode 100644 lessons/old/2021L/04-enums/result.rs create mode 100644 lessons/old/2021L/04-enums/tagged_union.cpp create mode 100644 lessons/old/2021L/05-tests/index.html create mode 100644 lessons/old/2021L/05-tests/test.rs create mode 100644 lessons/old/2021L/06-types-reasoning/basic_trait.rs create mode 100644 lessons/old/2021L/06-types-reasoning/generic_largest.rs create mode 100644 lessons/old/2021L/06-types-reasoning/generics.rs create mode 100644 lessons/old/2021L/06-types-reasoning/generics_fun.rs create mode 100644 lessons/old/2021L/06-types-reasoning/index.html create mode 100644 lessons/old/2021L/06-types-reasoning/lifetimes_basic.rs create mode 100644 lessons/old/2021L/06-types-reasoning/lifetimes_elision.rs create mode 100644 lessons/old/2021L/06-types-reasoning/non_generic.rs create mode 100644 lessons/old/2021L/06-types-reasoning/static_dynamic_dispatch.rs create mode 100644 lessons/old/2021L/06-types-reasoning/trait_default.rs create mode 100644 lessons/old/2021L/07-feedback/clippy.png create mode 100644 lessons/old/2021L/07-feedback/constructor.rs create mode 100644 lessons/old/2021L/07-feedback/index.html create mode 100644 lessons/old/2021L/07-feedback/number_conversions.rs create mode 100644 lessons/old/2021L/07-feedback/rustfmt.png create mode 100644 lessons/old/2021L/08-closures-iterators/index.html create mode 100644 lessons/old/2021L/09-feedback2/combinators.rs create mode 100644 lessons/old/2021L/09-feedback2/index.html create mode 100644 lessons/old/2021L/10-smart-pointers/box.rs create mode 100644 lessons/old/2021L/10-smart-pointers/deref_coercion.rs create mode 100644 lessons/old/2021L/10-smart-pointers/index.html create mode 100644 lessons/old/2021L/10-smart-pointers/ref_count.rs create mode 100644 lessons/old/2021L/10-smart-pointers/weak_ref.rs create mode 100644 lessons/old/2021L/11-feedback3/index.html create mode 100644 lessons/old/2021L/12-concurrency/index.html create mode 100644 lessons/old/2021L/13-design-patterns/index.html create mode 100644 lessons/old/2021L/14-async-1/index.html create mode 100644 lessons/old/2021L/15-async-2/index.html create mode 100644 lessons/old/2021L/16-macros/index.html create mode 100644 lessons/old/2021L/b1-rusty-graphs/index.html create mode 100644 lessons/old/2022Z/00-organizational/index.html create mode 100644 lessons/old/2022Z/01-introduction/clippy.jpg create mode 100644 lessons/old/2022Z/01-introduction/conditionals.rs create mode 100644 lessons/old/2022Z/01-introduction/cpp_meme.jpg create mode 100644 lessons/old/2022Z/01-introduction/errors_demo.c create mode 100644 lessons/old/2022Z/01-introduction/errors_demo.cpp create mode 100644 lessons/old/2022Z/01-introduction/errors_demo.rs create mode 100644 lessons/old/2022Z/01-introduction/functions.rs create mode 100644 lessons/old/2022Z/01-introduction/hello_world.rs create mode 100644 lessons/old/2022Z/01-introduction/index.html create mode 100644 lessons/old/2022Z/01-introduction/loops.rs create mode 100644 lessons/old/2022Z/01-introduction/students/gasinska.py create mode 100644 lessons/old/2022Z/01-introduction/students/grodzicki.py create mode 100644 lessons/old/2022Z/01-introduction/students/koszowski.go create mode 100644 lessons/old/2022Z/01-introduction/students/tudruj.cpp create mode 100644 lessons/old/2022Z/01-introduction/variables.rs create mode 100644 lessons/old/2022Z/02-ownership/index.html create mode 100644 lessons/old/2022Z/03-data-types/data_types.rs create mode 100644 lessons/old/2022Z/03-data-types/enums.c create mode 100644 lessons/old/2022Z/03-data-types/enums.rs create mode 100644 lessons/old/2022Z/03-data-types/index.html create mode 100644 lessons/old/2022Z/03-data-types/option.rs create mode 100644 lessons/old/2022Z/03-data-types/pattern_matching.rs create mode 100644 lessons/old/2022Z/03-data-types/result.rs create mode 100644 lessons/old/2022Z/03-data-types/tagged_union.cpp create mode 100644 lessons/old/2022Z/04-feedback-1/index.html create mode 100644 lessons/old/2022Z/05-types-reasoning/basic_trait.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/generic_largest.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/generics.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/generics_fun.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/index.html create mode 100644 lessons/old/2022Z/05-types-reasoning/lifetimes_basic.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/lifetimes_elision.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/non_generic.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/static_dynamic_dispatch.rs create mode 100644 lessons/old/2022Z/05-types-reasoning/trait_default.rs create mode 100644 lessons/old/2022Z/06-closures-iterators/index.html create mode 100644 lessons/old/2022Z/07-smart-pointers/box.rs create mode 100644 lessons/old/2022Z/07-smart-pointers/deref_coercion.rs create mode 100644 lessons/old/2022Z/07-smart-pointers/index.html create mode 100644 lessons/old/2022Z/07-smart-pointers/ref_count.rs create mode 100644 lessons/old/2022Z/07-smart-pointers/weak_ref.rs create mode 100644 lessons/old/2022Z/08-feedback-2/index.html create mode 100644 lessons/old/2022Z/09-concurrency/index.html create mode 100644 lessons/old/2022Z/10-design-patterns/index.html create mode 100644 lessons/old/2022Z/11-async-1/index.html create mode 100644 lessons/old/2022Z/12-project-feedback/index.html create mode 100644 lessons/project-showcase/fail-menu.png create mode 100644 lessons/project-showcase/game.png create mode 100644 lessons/project-showcase/graph_vis_demo.mkv create mode 100644 lessons/project-showcase/index.html create mode 100644 lessons/project-showcase/rusty-dungeon.png create mode 100644 robots.txt create mode 100644 search_index.en.js create mode 100644 sitemap.xml diff --git a/404.html b/404.html new file mode 100644 index 0000000..f8414f0 --- /dev/null +++ b/404.html @@ -0,0 +1,3 @@ + +404 Not Found +

404 Not Found

diff --git a/atom.xml b/atom.xml new file mode 100644 index 0000000..817e8a7 --- /dev/null +++ b/atom.xml @@ -0,0 +1,9224 @@ + + + Rust course + A Rust course at MIM UW + + + Zola + 2024-11-27T00:00:00+00:00 + https://mimuw-jnp2-rust.github.io/atom.xml + + Async: Part 1 + 2024-11-27T00:00:00+00:00 + 2024-11-27T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/11-async-1/ + + <h2 id="tokio">Tokio</h2> +<p>We'll use the <a href="https://tokio.rs/tokio/tutorial">Tokio tutorial</a> (chapters <code>Overview</code>-<code>Channels</code>).</p> +<h2 id="common-rust-lifetime-misconceptions">Common Rust Lifetime Misconceptions</h2> +<p>Please read <a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md">this blogpost</a>.</p> +<h2 id="assignment-6-graded">Assignment 6 (graded)</h2> +<p><a href="https://classroom.github.com/a/eYvC5SSn">Calculator</a></p> +<p>Deadline: 04.12.2024 23:59</p> + + + + + Fearless concurrency + 2024-11-14T00:00:00+00:00 + 2024-11-14T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/09-concurrency/ + + <h2 id="parallelism-vs-concurrency">Parallelism vs Concurrency</h2> +<p>Concurrency is when tasks <strong>can make</strong> progress <strong>independently</strong> of each other.</p> +<p>Parallelism is when multiple tasks <strong>make</strong> progress <strong>at the same time</strong>.</p> +<h1 id="concurrency-models-in-rust">Concurrency models in Rust</h1> +<h2 id="threads">Threads</h2> +<p>Nothing unusual here.</p> +<p>Threads can be created with the <code>thread::spawn</code> function <a href="https://doc.rust-lang.org/std/thread/fn.spawn.html">docs - please read them!</a>.</p> +<p>This method returns a <code>JoinHandle&lt;T&gt;</code> which can be used to wait for the thread to finish. <code>T</code> is the type of the thread's return value.</p> +<p>Another way to spawn threads is using <a href="https://doc.rust-lang.org/std/thread/fn.scope.html"><code>scope</code></a>. Threads created in such way are mandatorily joined at the end of the scope, which guarantees that they will borrow items for no longer that the lifetime of the scope. Hence, they can borrow non-<code>'static</code> items!</p> +<h4 id="propagating-panics">Propagating panics</h4> +<p>In Rust a panic of one thread doesn't affect the other threads (similar to how Java handles exceptions in threads).</p> +<h4 id="closures">Closures</h4> +<p>Closures which are used to create threads must take ownership of any values they use. It can be forced with the <code>move</code> keyword.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::thread; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> v </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> handle </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Here&#39;s a vector: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, v); +</span><span> }); +</span><span> +</span><span> handle.</span><span style="color:#4271ae;">join</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); +</span><span>} +</span></code></pre> +<p>Normal ownership rules still apply. It means that we cannot mutate the vector in the spawned thread from the main thread!</p> +<p>But what if we need to share some state?</p> +<h3 id="send-and-sync">Send and Sync</h3> +<p>They are marker traits used to indicate that a type or a reference to it can be used across threads. See the <a href="https://doc.rust-lang.org/nomicon/send-and-sync.html">nomicon</a> for more information.</p> +<blockquote> +<ul> +<li>A type is <code>Send</code> if it is safe to move it (<em>send</em> it) to another thread.</li> +<li>A type is <code>Sync</code> if it is safe to share (<em>sync</em>) between threads (<code>T</code> is <code>Sync</code> if and only if <code>&amp;T</code> is <code>Send</code>).</li> +</ul> +</blockquote> +<p>This makes sense, because <code>Sync</code> is about <em>sharing</em> object between threads, and <code>&amp;</code> is the <em>shared</em> reference.</p> +<p>There is also <a href="https://users.rust-lang.org/t/example-of-a-type-that-is-not-send/59835/3">a great answer on Rust forum</a>, listing + explaining example types that are <code>!Send</code> or <code>!Sync</code>.</p> +<p>For more convenient analysis, examples are listed here:</p> +<h4 id="send-sync"><code>Send + !Sync</code>:</h4> +<ul> +<li><code>UnsafeCell</code> (=&gt; <code>Cell</code>, <code>RefCell</code>);</li> +</ul> +<h4 id="send-sync-1"><code>!Send + !Sync</code>:</h4> +<ul> +<li><code>Rc</code></li> +<li><code>*const T</code>, <code>*mut T</code> (raw pointers)</li> +</ul> +<h4 id="send-sync-2"><code>!Send + Sync</code>:</h4> +<ul> +<li><code>MutexGuard</code> (hint: <code>!Send</code> for POSIX reasons)</li> +</ul> +<p>Exercise for the reader: explain reasons for all limitations of the above types.</p> +<h2 id="sharing-state-between-threads">Sharing state between threads</h2> +<h3 id="message-passing">Message passing</h3> +<p>One possible way is to use message passing. We can use a blocking queue (called <code>mpsc</code> - <a href="https://doc.rust-lang.org/std/sync/mpsc/index.html">&quot;multi producer single consumer FIFO queue&quot;</a>) to do it. +We talked about blocking queues in the Concurrent programming class. In Rust, they are strongly-typed. Sending and receiving ends have different types.</p> +<h3 id="mutexes">Mutexes</h3> +<p>In Rust, a mutex <em>wraps</em> a value and makes it thread-safe. +Because it becomes a part of the type, it's impossible to access the underlying value in an unsynchronized manner. It is conceptually similar to the <code>RefCell</code> type.</p> +<p><code>Arc</code> is a smart pointer like <code>Rc</code> but it can be shared between threads.</p> +<p>Please read more about them in <a href="https://doc.rust-lang.org/stable/book/ch16-03-shared-state.html">the book</a>.</p> +<p><a href="https://doc.rust-lang.org/std/sync/struct.Mutex.html">The docs</a> also mention <code>poisoning</code>.</p> +<h3 id="rwlocks">RwLocks</h3> +<p><a href="https://doc.rust-lang.org/std/sync/struct.RwLock.html">RwLocks</a> are similar to mutexes, but they distinguish between read and write locks.</p> +<h3 id="atomic-types">Atomic types</h3> +<p>Atomic types are described in <a href="https://doc.rust-lang.org/std/sync/atomic/">the docs</a>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Arc; +</span><span style="color:#8959a8;">use </span><span>std::sync::atomic::{AtomicUsize, Ordering}; +</span><span style="color:#8959a8;">use </span><span>std::{hint, thread}; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(AtomicUsize::new(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span> </span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> spinlock_clone.</span><span style="color:#4271ae;">store</span><span>(</span><span style="color:#f5871f;">0</span><span>, Ordering::SeqCst); +</span><span> }); +</span><span> +</span><span> </span><span style="color:#999999;">// Wait for the other thread to release the lock +</span><span> </span><span style="color:#8959a8;">while</span><span> spinlock.</span><span style="color:#4271ae;">load</span><span>(Ordering::SeqCst) </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Err</span><span>(panic) </span><span style="color:#3e999f;">=</span><span> thread.</span><span style="color:#4271ae;">join</span><span>() { +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread had an error: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, panic); +</span><span> } +</span><span>} +</span></code></pre> +<p>Note that <code>atomic</code> values don't have to be wrapped in a mutex when shared across threads.</p> +<h3 id="wait">Wait...</h3> +<p>If most types are <code>Sync + Send</code>, then what stops us from using a standard, non-atomic integer in the example above?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>spinlock_clone </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>}); +</span><span> +</span><span style="color:#8959a8;">while </span><span style="color:#3e999f;">*</span><span>spinlock </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span>} +</span></code></pre> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0594]: cannot assign to data in an `Arc` +</span><span> --&gt; src/main.rs:9:9 +</span><span> | +</span><span>9 | *spinlock_clone += 1; +</span><span> | ^^^^^^^^^^^^^^^^^^^^ cannot assign +</span><span> | +</span><span> = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc&lt;i32&gt;` +</span></code></pre> +<p>...so we would have to use a <code>RefCell</code> to be able to modify the value through a shared reference...</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(RefCell::new(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> +</span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>spinlock_clone.</span><span style="color:#4271ae;">borrow_mut</span><span>() </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>}); +</span><span> +</span><span style="color:#999999;">// Wait for the other thread to release the lock +</span><span style="color:#8959a8;">while </span><span style="color:#3e999f;">*</span><span>spinlock.</span><span style="color:#4271ae;">borrow</span><span>() </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span>} +</span></code></pre> +<p>...but <code>RefCell</code> isn't <code>Sync</code>:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0277]: `RefCell&lt;i32&gt;` cannot be shared between threads safely +</span><span> --&gt; src/main.rs:9:18 +</span><span> | +</span><span>9 | let thread = thread::spawn(move|| { +</span><span> | ^^^^^^^^^^^^^ `RefCell&lt;i32&gt;` cannot be shared between threads safely +</span><span> | +</span><span> = help: the trait `Sync` is not implemented for `RefCell&lt;i32&gt;` +</span><span> = note: required because of the requirements on the impl of `Send` for `Arc&lt;RefCell&lt;i32&gt;&gt;` +</span><span> = note: required because it appears within the type `[closure@src/main.rs:9:32: 11:6]` +</span><span>note: required by a bound in `spawn` +</span></code></pre> +<p>And that bound mentioned in the last line looks like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">spawn</span><span>&lt;F, T&gt;(</span><span style="color:#f5871f;">f</span><span>: F) -&gt; JoinHandle&lt;T&gt; </span><span style="color:#8959a8;">where +</span><span> F: FnOnce() -&gt; T, +</span><span> F: Send + </span><span style="color:#8959a8;">&#39;static</span><span>, +</span><span> T: Send + </span><span style="color:#8959a8;">&#39;static</span><span>, +</span></code></pre> +<h4 id="exercise-for-the-reader">Exercise for the reader</h4> +<p>Why is it impossible to share a reference to a <code>Mutex</code> between threads spawned with <code>std::thread::spawn</code>?</p> +<h2 id="data-parallelism-with-rayon">Data parallelism with Rayon</h2> +<p><a href="https://docs.rs/rayon/latest/rayon/">Rayon</a> is a library for parallelization of data processing. +It can be used to parallelize the execution of functions over a collection of data by switching the standard <code>Iterator</code> to a <code>ParallelIterator</code>. +It works very similar to <a href="https://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html#executing_streams_in_parallel">Java's parallel streams</a>.</p> +<p>Why do that? Because thread synchronization is hard! <a href="https://doc.rust-lang.org/nomicon/races.html">Rust prevents data races</a>, but <a href="https://users.rust-lang.org/t/deadlock-is-it-a-bug-or-is-it-intentional/1544">logical races and deadlocks are impossible to prevent!</a>!</p> +<p><a href="https://github.com/rayon-rs/rayon/blob/master/FAQ.md">Rayon's FAQ</a> is worth reading.</p> +<h2 id="reading">Reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/book/ch16-00-concurrency.html">The Book</a></li> +<li><a href="http://archive.today/WFlZV">Safely writing code that isn't thread-safe</a></li> +</ul> +<h2 id="no-assignment-this-week">No assignment this week</h2> +<p>Please work on the first iteration of the big project instead.</p> + + + + + Closures and Iterators + 2024-10-30T00:00:00+00:00 + 2024-10-30T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/06-closures-iterators/ + + <h1 id="closures">Closures</h1> +<p>Closures (Polish: &quot;domknięcia&quot;) are anonymous functions that can access variables from the scope in which they were defined.</p> +<h2 id="closure-syntax">Closure syntax</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> #[</span><span style="color:#c82829;">rustfmt</span><span>::</span><span style="color:#c82829;">skip</span><span>] +</span><span> { +</span><span> </span><span style="color:#999999;">// This is formatted so that without rust-analyzer it renders as well-aligned. +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">add_one_v1 </span><span>(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#8959a8;">u32</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ x </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">1 </span><span>} </span><span style="color:#999999;">// This is an ordinary function. +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">add_one_v2 </span><span style="color:#3e999f;">= </span><span>|</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#8959a8;">u32</span><span>| -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ x </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">1 </span><span>}; </span><span style="color:#999999;">// Closures use pipes instead of parentheses. +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">add_one_v3 </span><span style="color:#3e999f;">= </span><span>|</span><span style="color:#f5871f;">x</span><span>| { x </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">1 </span><span>}; </span><span style="color:#999999;">// Both parameters and return value can have their types inferred. +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">add_one_v4 </span><span style="color:#3e999f;">= </span><span>|</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">1 </span><span>; </span><span style="color:#999999;">// If the body is a single expression, braces can be omitted. +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _res </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">add_one_v1</span><span>(</span><span style="color:#f5871f;">0_</span><span style="color:#8959a8;">u32</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> _res </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">add_one_v2</span><span>(</span><span style="color:#f5871f;">0_</span><span style="color:#8959a8;">u32</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> _res </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">add_one_v3</span><span>(</span><span style="color:#f5871f;">0_</span><span style="color:#8959a8;">u32</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> _res </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">add_one_v4</span><span>(</span><span style="color:#f5871f;">0_</span><span style="color:#8959a8;">u32</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// This does not compile, because closures are not generic. +</span><span> </span><span style="color:#999999;">// Their type is inferred once and stays the same. +</span><span> </span><span style="color:#999999;">// let _res = add_one_v4(0_i32); +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/06-closures-iterators/closures_syntax.rs">closures_syntax.rs</a>)</sub></p> +<h2 id="closures-types">Closures' types</h2> +<p>Closures are unnameable types. That is, each closure gets its own unique type from the compiler, +but we cannot name it. Therefore, closures' types must be inferred. +We will often use <code>impl</code> keyword with closure traits (e.g., <code>impl Fn</code>) - those traits are described below.</p> +<h2 id="closures-capture-environment">Closures capture environment</h2> +<p>Closures can capture variables from the environment where they are defined. They can do that in two ways:</p> +<ul> +<li>Capturing References (borrowing), or</li> +<li>Moving Ownership.</li> +</ul> +<p><strong>HOW</strong> closures capture variables is one thing. +But even more important is <strong>WHAT</strong> closures do with their captures.</p> +<h3 id="functions-closures-hierarchy">Functions &amp; closures hierarchy</h3> +<p>Based on <strong>WHAT</strong> a closure does with its captures, it implements closure traits:</p> +<ul> +<li><code>FnOnce</code> - closures that may move out of their captures environment (and thus called once).</li> +<li><code>FnMut</code> - closures that may mutate their captures, but don't move out of their captures environment (so can be called multiple times, but require a mutable reference);</li> +<li><code>Fn</code> - closures that do not mutate their captures (so can be called multiple times through an immutable reference).</li> +</ul> +<p>For completeness, there is a (concrete) type of function pointers:</p> +<ul> +<li><code>fn</code> - functions, closures with no captures.</li> +</ul> +<p>Those traits and the <code>fn</code> type form a hierarchy: <code>fn</code> ⊆ <code>Fn</code> ⊆ <code>FnMut</code> ⊆ <code>FnOnce</code></p> +<!--> $$ fn \subseteq Fn \subseteq FnMut \subseteq FnOnce $$ --> +<p>The following code sample demonstrates various ways to capture environment (borrowing or moving) and various kinds of closures, based on what they do with their captures:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#4271ae;">borrowing_immutably_closure</span><span>(); +</span><span> </span><span style="color:#4271ae;">borrowing_mutably_closure</span><span>(); +</span><span> </span><span style="color:#4271ae;">moving_in_nonmutating_closure</span><span>(); +</span><span> </span><span style="color:#4271ae;">moving_in_mutating_closure</span><span>(); +</span><span> </span><span style="color:#4271ae;">moving_in_moving_out_closure</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">borrowing_immutably_closure</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> println!(</span><span style="color:#718c00;">&quot;Before defining closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span> +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">only_borrows </span><span style="color:#3e999f;">= </span><span>|| println!(</span><span style="color:#718c00;">&quot;From closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span> +</span><span> </span><span style="color:#999999;">// This would not really only borrow... (it needs Vec by value). +</span><span> </span><span style="color:#999999;">// let only_borrows = || std::mem::drop::&lt;Vec&lt;_&gt;&gt;(list); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Before calling closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span> </span><span style="color:#4271ae;">only_borrows</span><span>(); +</span><span> println!(</span><span style="color:#718c00;">&quot;After calling closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">borrowing_mutably_closure</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> println!(</span><span style="color:#718c00;">&quot;Before defining closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut </span><span style="color:#4271ae;">borrows_mutably </span><span style="color:#3e999f;">= </span><span>|| list.</span><span style="color:#4271ae;">push</span><span>(</span><span style="color:#f5871f;">7</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// println!(&quot;Before calling closure: {:?}&quot;, list); +</span><span> </span><span style="color:#4271ae;">borrows_mutably</span><span>(); +</span><span> println!(</span><span style="color:#718c00;">&quot;After calling closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">moving_in_nonmutating_closure</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> println!(</span><span style="color:#718c00;">&quot;Before defining closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span> +</span><span> </span><span style="color:#999999;">// This closure would just borrow the list, because it only prints it. +</span><span> </span><span style="color:#999999;">// However, as spawning threads require passing `impl FnOnce + &#39;static`, +</span><span> </span><span style="color:#999999;">// we need to use `move` keyword to force the closure to move `list` +</span><span> </span><span style="color:#999999;">// into its captured environment. +</span><span> std::thread::spawn(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>println!(</span><span style="color:#718c00;">&quot;From thread: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list)) +</span><span> .</span><span style="color:#4271ae;">join</span><span>() +</span><span> .</span><span style="color:#4271ae;">unwrap</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">moving_in_mutating_closure</span><span>() { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">append_42</span><span>(</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">appender</span><span>: impl FnMut(</span><span style="color:#f5871f;">i32</span><span>)) { +</span><span> </span><span style="color:#4271ae;">appender</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> appender </span><span style="color:#3e999f;">= </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> println!(</span><span style="color:#718c00;">&quot;Before defining closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, list); +</span><span> +</span><span> </span><span style="color:#999999;">// The `move` keyword is necessary to prevent dangling reference to `list`. +</span><span> </span><span style="color:#999999;">// Of course, the borrow checker protects us from compiling code without `move`. +</span><span> </span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|</span><span>num</span><span style="color:#3e999f;">|</span><span> list.</span><span style="color:#4271ae;">push</span><span>(num) +</span><span> }; +</span><span> +</span><span> </span><span style="color:#4271ae;">append_42</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> appender); +</span><span> </span><span style="color:#4271ae;">append_42</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> appender); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">moving_in_moving_out_closure</span><span>() { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">append_multiple_times</span><span>(</span><span style="color:#f5871f;">appender</span><span>: impl FnOnce(&amp;</span><span style="color:#f5871f;">mut Vec</span><span>&lt;</span><span style="color:#f5871f;">String</span><span>&gt;) + Clone) { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> list </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Vec</span><span>::new(); +</span><span> +</span><span> </span><span style="color:#999999;">// We can clone this `FnOnce`, because we additionally require `Clone`. +</span><span> </span><span style="color:#999999;">// If we didn&#39;t clone it, we couldn&#39;t call it more than *once*. +</span><span> appender.</span><span style="color:#4271ae;">clone</span><span>()(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> list); +</span><span> </span><span style="color:#4271ae;">appender</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> list); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> appender </span><span style="color:#3e999f;">= </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> string </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Ala&quot;</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;Before defining closure: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, string); +</span><span> +</span><span> </span><span style="color:#999999;">// The `move` keyword is necessary to prevent dangling reference to `list`. +</span><span> </span><span style="color:#999999;">// Of course, the borrow checker protects us from compiling code without `move`. +</span><span> </span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|</span><span>list: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c99e00;">Vec</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt;</span><span style="color:#3e999f;">|</span><span> list.</span><span style="color:#4271ae;">push</span><span>(string) +</span><span> }; +</span><span> +</span><span> </span><span style="color:#999999;">// As `appender` is only `FnOnce`, we need to clone before we consume it by calling it. +</span><span> </span><span style="color:#4271ae;">append_multiple_times</span><span>(appender.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">append_multiple_times</span><span>(appender); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/06-closures-iterators/closures_capturing.rs">closures_capturing.rs</a>)</sub></p> +<h3 id="closures-as-trait-objects-in-dynamic-dispatch">Closures as trait objects (in dynamic dispatch)</h3> +<p>The following code sample shows how one can use closures as <code>dyn Trait</code> objects, bypassing the problem of them having anonymous types:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">some_function</span><span>() -&gt; String { +</span><span> </span><span style="color:#c99e00;">String</span><span>::new() +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> v1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;v1&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let mut </span><span style="color:#4271ae;">borrowing_immutably_closure </span><span style="color:#3e999f;">= </span><span>|| v1.</span><span style="color:#4271ae;">clone</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> v2 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;v2&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let mut </span><span style="color:#4271ae;">borrowing_mutably_closure </span><span style="color:#3e999f;">= </span><span>|| { +</span><span> v2.</span><span style="color:#4271ae;">push</span><span>(</span><span style="color:#718c00;">&#39;.&#39;</span><span>); +</span><span> v2.</span><span style="color:#4271ae;">clone</span><span>() +</span><span> }; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> v3 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;v3&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let mut</span><span> moving_in_nonmutating_closure </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">||</span><span> v3.</span><span style="color:#4271ae;">clone</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> v4 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;v4&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let mut</span><span> moving_in_mutating_closure </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> v4.</span><span style="color:#4271ae;">push</span><span>(</span><span style="color:#718c00;">&#39;.&#39;</span><span>); +</span><span> v4.</span><span style="color:#4271ae;">clone</span><span>() +</span><span> }; +</span><span> </span><span style="color:#8959a8;">let</span><span> v5 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;v5&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">moving_in_moving_out_closure </span><span style="color:#3e999f;">= </span><span>|| v5; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> fn_once_callables: [</span><span style="color:#3e999f;">&amp;</span><span>dyn </span><span style="color:#c99e00;">FnOnce</span><span>() -&gt; String; </span><span style="color:#f5871f;">5</span><span>] </span><span style="color:#3e999f;">= </span><span>[ +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>some_function, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>borrowing_immutably_closure, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>borrowing_mutably_closure, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>moving_in_nonmutating_closure, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>moving_in_moving_out_closure, +</span><span> ]; +</span><span> +</span><span> #[</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> </span><span style="color:#8959a8;">for</span><span> fn_once_callable </span><span style="color:#3e999f;">in</span><span> fn_once_callables { +</span><span> </span><span style="color:#999999;">// Cannot move a value of type `dyn FnOnce() -&gt; String`. +</span><span> </span><span style="color:#999999;">// The size of `dyn FnOnce() -&gt; String` cannot be statically determined. +</span><span> </span><span style="color:#999999;">// println!(&quot;{}&quot;, fn_once_callable()); +</span><span> +</span><span> </span><span style="color:#999999;">// So, for FnOnce, we need to be their owners to be able to call them, +</span><span> </span><span style="color:#999999;">// and we can&#39;t have a `dyn` object owned on stack. +</span><span> </span><span style="color:#999999;">// We will solve this problem soon with smart pointers (e.g., Box). +</span><span> </span><span style="color:#999999;">// This will give us `std::function` -like experience. +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Mutable reference to FnMut is required to be able to call it. +</span><span> </span><span style="color:#8959a8;">let</span><span> fn_mut_callables: [</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> dyn </span><span style="color:#c99e00;">FnMut</span><span>() -&gt; String; </span><span style="color:#f5871f;">4</span><span>] </span><span style="color:#3e999f;">= </span><span>[ +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> borrowing_immutably_closure, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> borrowing_mutably_closure, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> moving_in_nonmutating_closure, +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> moving_in_mutating_closure, +</span><span> ]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for</span><span> fn_mut_callable </span><span style="color:#3e999f;">in</span><span> fn_mut_callables { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#4271ae;">fn_mut_callable</span><span>()); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> fn_callables: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#3e999f;">&amp;</span><span>dyn </span><span style="color:#c99e00;">Fn</span><span>() -&gt; String] </span><span style="color:#3e999f;">= +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#3e999f;">&amp;</span><span>borrowing_immutably_closure, </span><span style="color:#3e999f;">&amp;</span><span>moving_in_nonmutating_closure]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for</span><span> fn_callable </span><span style="color:#3e999f;">in</span><span> fn_callables { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#4271ae;">fn_callable</span><span>()); +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/06-closures-iterators/closures_fun.rs">closures_fun.rs</a>)</sub></p> +<h2 id="examples">Examples</h2> +<p>We'll go through the examples from <a href="https://doc.rust-lang.org/rust-by-example/fn/closures.html">Rust by Example</a>. +More examples will be seen when working with iterators.</p> +<h1 id="iterators">Iterators</h1> +<p>In Rust, there is no hierarchy of types for collections (because there is no inheritance in general). +Instead, what makes a collection is that it can be iterated over.</p> +<p>A usual way in Rust to perform an iteration over something, be it a range of values or items in a collection, is creating a (lazy) iterator over it and transforming it using <em>iterator adaptors</em>. For example, if <code>T: Iterator</code>, then <code>T::map()</code> creates a <code>Map&lt;T&gt;</code> adaptor. Once a final iterator is created, it has to be actually activated (iterated over), which is most commonly done by:</p> +<ul> +<li>exhausting it with the <code>for</code> loop,</li> +<li>manually iterating over it using <code>next()</code> calls,</li> +<li>collecting its contents into inferred collection (<code>collect()</code>),</li> +<li>consuming it with a <em>consuming adaptor</em> (e.g., <code>sum()</code>, <code>count</code>),</li> +</ul> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::collections::HashSet; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// Various ways to create a String. +</span><span> </span><span style="color:#8959a8;">let mut</span><span> strings </span><span style="color:#3e999f;">= </span><span>[ +</span><span> </span><span style="color:#c99e00;">String</span><span>::new(), +</span><span> </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a&quot;</span><span>), +</span><span> </span><span style="color:#718c00;">&quot;b&quot;</span><span>.</span><span style="color:#4271ae;">into</span><span>(), +</span><span> </span><span style="color:#718c00;">&quot;c&quot;</span><span>.</span><span style="color:#4271ae;">to_owned</span><span>(), +</span><span> </span><span style="color:#718c00;">&quot;d&quot;</span><span>.</span><span style="color:#4271ae;">to_string</span><span>(), +</span><span> </span><span style="color:#718c00;">&quot;e&quot;</span><span>.</span><span style="color:#4271ae;">chars</span><span>().</span><span style="color:#4271ae;">collect</span><span>(), +</span><span> ]; +</span><span> +</span><span> </span><span style="color:#999999;">// `iter()` is a usual method that creates an iterator over immutable references to the collection&#39;s items. +</span><span> </span><span style="color:#8959a8;">let</span><span> _all_len_0_or_1 </span><span style="color:#3e999f;">=</span><span> strings +</span><span> .</span><span style="color:#4271ae;">iter</span><span>() +</span><span> .</span><span style="color:#4271ae;">filter</span><span>(|</span><span style="color:#f5871f;">s</span><span>| </span><span style="color:#3e999f;">!</span><span>s.</span><span style="color:#4271ae;">is_empty</span><span>()) +</span><span> .</span><span style="color:#4271ae;">all</span><span>(|</span><span style="color:#f5871f;">s</span><span>| s.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// `iter_mut()` is a usual method that creates an iterator over mutable references to the collection&#39;s items. +</span><span> </span><span style="color:#8959a8;">for</span><span> s </span><span style="color:#3e999f;">in</span><span> strings.</span><span style="color:#4271ae;">iter_mut</span><span>().</span><span style="color:#4271ae;">map_while</span><span>(|</span><span style="color:#f5871f;">s</span><span>| </span><span style="color:#8959a8;">match</span><span> s.</span><span style="color:#4271ae;">as_str</span><span>() { +</span><span> </span><span style="color:#718c00;">&quot;c&quot; </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c99e00;">None</span><span>, +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span style="color:#c99e00;">Some</span><span>(s), +</span><span> }) { +</span><span> </span><span style="color:#3e999f;">*</span><span>s </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#718c00;">&quot;b&quot;</span><span>, </span><span style="color:#718c00;">&quot;aba&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// This code is equivalent to the `for` above. +</span><span> </span><span style="color:#999999;">// `for` is usually more idiomatic, but `for_each` is sometimes cleaner and sometimes faster. +</span><span> strings +</span><span> .</span><span style="color:#4271ae;">iter_mut</span><span>() +</span><span> .</span><span style="color:#4271ae;">map_while</span><span>(|</span><span style="color:#f5871f;">s</span><span>| </span><span style="color:#8959a8;">match</span><span> s.</span><span style="color:#4271ae;">as_str</span><span>() { +</span><span> </span><span style="color:#718c00;">&quot;c&quot; </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c99e00;">None</span><span>, +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span style="color:#c99e00;">Some</span><span>(s), +</span><span> }) +</span><span> .</span><span style="color:#4271ae;">for_each</span><span>(|</span><span style="color:#f5871f;">s</span><span>| </span><span style="color:#3e999f;">*</span><span>s </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#718c00;">&quot;b&quot;</span><span>, </span><span style="color:#718c00;">&quot;aba&quot;</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// `into_iter()` is a method from `IntoIterator` trait that converts a collection to an iterator +</span><span> </span><span style="color:#8959a8;">let mut</span><span> empty_strings_iter </span><span style="color:#3e999f;">=</span><span> strings.</span><span style="color:#4271ae;">into_iter</span><span>().</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">s</span><span>| { +</span><span> s.</span><span style="color:#4271ae;">clear</span><span>(); +</span><span> s +</span><span> }); +</span><span> +</span><span> </span><span style="color:#999999;">// This is a set of empty Strings... +</span><span> </span><span style="color:#8959a8;">let</span><span> empty_strings_set </span><span style="color:#3e999f;">=</span><span> empty_strings_iter.</span><span style="color:#4271ae;">clone</span><span>().collect::&lt;HashSet&lt;</span><span style="color:#3e999f;">_</span><span>&gt;&gt;(); +</span><span> +</span><span> </span><span style="color:#999999;">// And this is a Vec of immutable references to empty Strings. +</span><span> </span><span style="color:#8959a8;">let</span><span> empty_string_refs_vec </span><span style="color:#3e999f;">=</span><span> empty_strings_set.</span><span style="color:#4271ae;">iter</span><span>().collect::&lt;</span><span style="color:#c99e00;">Vec</span><span>&lt;</span><span style="color:#3e999f;">_</span><span>&gt;&gt;(); +</span><span> +</span><span> </span><span style="color:#999999;">// equivalent to `empty_string_refs_vec.into_iter()` +</span><span> </span><span style="color:#8959a8;">for</span><span> s </span><span style="color:#3e999f;">in</span><span> empty_string_refs_vec { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s) +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">while let </span><span style="color:#c99e00;">Some</span><span>(s) </span><span style="color:#3e999f;">=</span><span> empty_strings_iter.</span><span style="color:#4271ae;">next_back</span><span>() { +</span><span> assert!(s.</span><span style="color:#4271ae;">is_empty</span><span>()); +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/06-closures-iterators/iterator_exhaustion.rs">iterator_exhaustion.rs</a>)</sub></p> +<p>Iterators are highly optimised, so they are high-level code that compiles down to simple and optimised machine code (intended as <em>zero-cost abstractions</em>).</p> +<p>We'll go through the official <a href="https://doc.rust-lang.org/stable/std/iter/">docs</a>.</p> +<ul> +<li>Most methods are defined in the <a href="https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html">Iterator trait</a>.</li> +<li><a href="https://doc.rust-lang.org/stable/std/iter/trait.IntoIterator.html">IntoIterator</a> is also worth noting, because it makes types work with the <code>for</code> loop.</li> +<li>For completeness, there is <a href="https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html">FromIterator</a>, which is required for <code>collect()</code> to work.</li> +</ul> +<h1 id="reading">Reading</h1> +<ul> +<li><a href="https://doc.rust-lang.org/book/ch12-00-an-io-project.html">The Book, chapter 12 (that's a project!)</a></li> +<li><a href="https://doc.rust-lang.org/book/ch13-00-functional-features.html">The Book, chapter 13</a></li> +<li><a href="https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html">The Book, chapter 14</a></li> +<li><a href="https://doc.rust-lang.org/stable/book/ch19-05-advanced-functions-and-closures.html">The Book, Advanced Functions and Closures</a></li> +<li><a href="https://doc.rust-lang.org/stable/book/ch19-03-advanced-traits.html">The Book, Advanced Traits</a></li> +</ul> +<h2 id="assignment-4-graded">Assignment 4 (graded)</h2> +<p><a href="https://classroom.github.com/a/9aJix-LK">Lazy</a></p> +<p>Deadline: 06.11.2024 23:59</p> + + + + + Reasoning About Types + 2024-10-24T00:00:00+00:00 + 2024-10-24T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/ + + <h1 id="type-traits">Type traits</h1> +<p>Traits are a way to defined common behavior between different types. They can be compared to <em>interfaces</em> from many other mainstream languages or to type classes from Haskell, however, Rust is not an object-oriented language and there are some notable differences between type traits and Java interfaces.</p> +<p>The way we describe behavior in Rust is through methods. Traits consist of a set of these methods which then should be implemented by a type. We've already encountered examples of these, like the <code>Clone</code> trait which specified that the <code>clone()</code> method can be called on some given type. Now, let's take a deeper look and try defining our own trait.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Summary { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.username, </span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.</span><span style="color:#4271ae;">summarize</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/basic_trait.rs">basic_trait.rs</a>)</sub></p> +<h2 id="default-implementations">Default implementations</h2> +<p>Trait definitions can also be provided with default implementations of behaviors.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Upload { +</span><span> </span><span style="color:#c82829;">filename</span><span>: String, +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span style="color:#8959a8;">struct </span><span>Photo { +</span><span> </span><span style="color:#c82829;">filename</span><span>: String, +</span><span> </span><span style="color:#c82829;">width</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">height</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Description { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">describe</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;No description available.&quot;</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// All default implementations +</span><span style="color:#8959a8;">impl </span><span>Description </span><span style="color:#8959a8;">for </span><span>Upload {} +</span><span> +</span><span style="color:#999999;">// Default implementations can be overwritten +</span><span style="color:#8959a8;">impl </span><span>Description </span><span style="color:#8959a8;">for </span><span>Photo { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">describe</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;"> x </span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.filename, </span><span style="color:#c82829;">self</span><span>.width, </span><span style="color:#c82829;">self</span><span>.height) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// Default implementations can rely on methods with no defaults +</span><span style="color:#8959a8;">trait </span><span>Size { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">width</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32</span><span>; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">height</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">size</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">width</span><span>() </span><span style="color:#3e999f;">* </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">height</span><span>() +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Size </span><span style="color:#8959a8;">for </span><span>Photo { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">width</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.width +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">height</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.height +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Using default impl of `size()` +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> upload </span><span style="color:#3e999f;">=</span><span> Upload { +</span><span> filename: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;notes.txt&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Upload: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, upload.</span><span style="color:#4271ae;">describe</span><span>()); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> photo </span><span style="color:#3e999f;">=</span><span> Photo { +</span><span> filename: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;stock_crustacean.png&quot;</span><span>), +</span><span> width: </span><span style="color:#f5871f;">100</span><span>, +</span><span> height: </span><span style="color:#f5871f;">150</span><span>, +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Photo: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, photo.</span><span style="color:#4271ae;">describe</span><span>()); +</span><span> println!(</span><span style="color:#718c00;">&quot;Size: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, photo.</span><span style="color:#4271ae;">size</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/trait_default.rs">trait_default.rs</a>)</sub></p> +<h2 id="what-about-derive">What about <em>derive</em>?</h2> +<p>There is a trait-related thing we have used quite extensively and not explained yet, namely the <code>#[derive]</code> attribute. What it does is generate items (in our case a trait implementation) based on the given data definition (here a struct). Below you can find a list of derivable traits from the standard library. Writing derivation rules for user defined traits is also possible, but goes out of the scope of this lesson.</p> +<p>Derivable traits:</p> +<ul> +<li> +<p>Equality traits: <code>Eq</code>, <code>PartialEq</code> and comparison traits: <code>Ord</code> and <code>PartialOrd</code>. The <code>Partial-</code> versions exist because there are types which don't fulfill the reflexivity requirement of equality (<code>NaN != NaN</code>) or do not form a total order (<code> NaN &lt; 0.0 == false</code> and <code>NaN &gt;= 0.0 == false</code>).</p> +</li> +<li> +<p>Data duplication traits: <code>Clone</code> and <code>Copy</code></p> +</li> +<li> +<p><code>Hash</code> - allows using values of that type as keys in a hashmap</p> +</li> +<li> +<p><code>Default</code> - provides a zero-arg constructor function</p> +</li> +<li> +<p><code>Debug</code> - provides a formatting of the value which can be used in debugging context. It should <em>NOT</em> be implemented manually. In general, if it's possible to derive the <code>Debug</code>, there are no reasons against doing it.</p> +</li> +</ul> +<h3 id="when-is-it-possible-to-derive-a-trait">When is it possible to derive a trait?</h3> +<p>When all fields of a struct/variants of an enum implement that trait.</p> +<h3 id="should-all-traits-always-be-derived-if-it-is-possible">Should all traits always be derived if it is possible?</h3> +<p>No. Although it may be tempting to just slap <code>#[derive(Clone, Copy)]</code> everywhere, it would be counter-effective. For example, at some later point you might add a non-Copy field to the struct and your (or, what's worse, someone else's!) code would break. Another example: it makes little sense to use containers as keys in hashmaps or to compare tweets.</p> +<h1 id="generics">Generics</h1> +<p>Suppose we want to find the largest element in a sequence and return it. Very much on purpose, we didn't specify what type these elements would be - ideally, we would love it to work on all types that have a defined notion of a <em>largest</em> element. However, to make things simpler for now, let's focus only on two primitive types: <code>i32</code> and <code>char</code>. Let's try to write the code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest_i32</span><span>(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">i32</span><span>]) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest_char</span><span>(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">char</span><span>]) -&gt; </span><span style="color:#8959a8;">char </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> number_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">34</span><span>, </span><span style="color:#f5871f;">50</span><span>, </span><span style="color:#f5871f;">25</span><span>, </span><span style="color:#f5871f;">100</span><span>, </span><span style="color:#f5871f;">65</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest_i32</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>number_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest number is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> char_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#718c00;">&#39;y&#39;</span><span>, </span><span style="color:#718c00;">&#39;m&#39;</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>, </span><span style="color:#718c00;">&#39;q&#39;</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest_char</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>char_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest char is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/non_generic.rs">non_generic.rs</a>)</sub></p> +<p>Perfect, it works! Now only twenty more types to go...</p> +<p>Fortunately, Rust gives us a way to avoid all this code duplication and generalize the types we're working on.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span></code></pre> +<p>Cleaner already - we merged possibly very many implementations into one. But, when we try to compile this:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0369]: binary operation `&gt;` cannot be applied to type `T` +</span><span> --&gt; src/main.rs:5:17 +</span><span> | +</span><span>5 | if item &gt; largest { +</span><span> | ---- ^ ------- T +</span><span> | | +</span><span> | T +</span><span> | +</span><span>help: consider restricting type parameter `T` +</span><span> | +</span><span>1 | fn largest&lt;T: std::cmp::PartialOrd&gt;(list: &amp;[T]) -&gt; T { +</span><span> | ++++++++++++++++++++++ +</span></code></pre> +<p>Since <code>T</code> can be of absolutely any type now, the compiler cannot be sure that operator <code>&gt;</code> is defined. This aligns with what we wanted, as without comparing elements we don't have a notion of the largest one either. As always, the compiler comes to our aid:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd</span><span>&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span></code></pre> +<p>We call this a <em>trait bound</em>, a way to provide constraints on what kind of types we are talking about in a given context. This implementation almost works now. Let's look at the new error.</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0508]: cannot move out of type `[T]`, a non-copy slice +</span><span> --&gt; src/main.rs:2:23 +</span><span> | +</span><span>2 | let mut largest = list[0]; +</span><span> | ^^^^^^^ +</span><span> | | +</span><span> | cannot move out of here +</span><span> | move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait +</span><span> | help: consider borrowing here: `&amp;list[0]` +</span><span> +</span><span>error[E0507]: cannot move out of a shared reference +</span><span> --&gt; src/main.rs:4:18 +</span><span> | +</span><span>4 | for &amp;item in list { +</span><span> | ----- ^^^^ +</span><span> | || +</span><span> | |data moved here +</span><span> | |move occurs because `item` has type `T`, which does not implement the `Copy` trait +</span><span> | help: consider removing the `&amp;`: `item` +</span></code></pre> +<p>Our function attempts to take ownership, but, again, the compiler doesn't know whether <code>T</code> can just be trivially copied. Rust allows us to combine multiple trait bounds together:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd </span><span style="color:#3e999f;">+ </span><span style="color:#c99e00;">Copy</span><span>&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> number_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">34</span><span>, </span><span style="color:#f5871f;">50</span><span>, </span><span style="color:#f5871f;">25</span><span>, </span><span style="color:#f5871f;">100</span><span>, </span><span style="color:#f5871f;">65</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>number_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest number is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> char_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#718c00;">&#39;y&#39;</span><span>, </span><span style="color:#718c00;">&#39;m&#39;</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>, </span><span style="color:#718c00;">&#39;q&#39;</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>char_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest char is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/generic_largest.rs">generic_largest.rs</a>)</sub></p> +<h2 id="a-powerful-tool">A powerful tool</h2> +<p>There's a lot more that we can do with generics:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Debug; +</span><span> +</span><span style="color:#999999;">// generic enums +</span><span style="color:#8959a8;">enum </span><span>OurOption&lt;T&gt; { +</span><span> </span><span style="color:#c99e00;">Some</span><span>(T), +</span><span> </span><span style="color:#c99e00;">None</span><span>, +</span><span>} +</span><span> +</span><span style="color:#999999;">// generic structs +</span><span style="color:#8959a8;">struct </span><span>Tuple2&lt;T, U&gt; { +</span><span> </span><span style="color:#c82829;">x</span><span>: T, +</span><span> </span><span style="color:#c82829;">y</span><span>: U, +</span><span>} +</span><span> +</span><span style="color:#999999;">// generic implementation +</span><span style="color:#8959a8;">impl</span><span>&lt;T, U&gt; Tuple2&lt;T, U&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: T, </span><span style="color:#f5871f;">y</span><span>: U) -&gt; </span><span style="color:#8959a8;">Self </span><span>{ +</span><span> </span><span style="color:#8959a8;">Self </span><span>{ x, y } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Pair&lt;T&gt; { +</span><span> </span><span style="color:#c82829;">x</span><span>: T, +</span><span> </span><span style="color:#c82829;">y</span><span>: T, +</span><span>} +</span><span> +</span><span style="color:#999999;">// conditional implementation +</span><span style="color:#8959a8;">impl</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd </span><span style="color:#3e999f;">+ </span><span style="color:#c99e00;">Copy</span><span>&gt; Pair&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; T { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.x </span><span style="color:#3e999f;">&gt; </span><span style="color:#c82829;">self</span><span>.y { +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.y +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// alternative syntax +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; Pair&lt;T&gt; +</span><span style="color:#8959a8;">where +</span><span> T: PartialOrd + Copy, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">smallest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; T { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.x </span><span style="color:#3e999f;">&lt; </span><span style="color:#c82829;">self</span><span>.y { +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.y +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// Here information about the concrete underlying type is preserved. +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">cloning_machine</span><span>&lt;T: </span><span style="color:#c99e00;">Clone </span><span style="color:#3e999f;">+</span><span> Debug&gt;(</span><span style="color:#f5871f;">item</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>T) -&gt; T { +</span><span> item.</span><span style="color:#4271ae;">clone</span><span>() +</span><span>} +</span><span> +</span><span style="color:#999999;">// Here information about the concrete underlying type is erased. +</span><span style="color:#999999;">// We can only either format or clone the result. +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">erasing_cloning_machine1</span><span>(</span><span style="color:#f5871f;">item</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>(</span><span style="color:#f5871f;">impl Clone</span><span> + </span><span style="color:#f5871f;">Debug</span><span>)) -&gt; impl Clone </span><span style="color:#3e999f;">+</span><span> Debug { +</span><span> item.</span><span style="color:#4271ae;">clone</span><span>() +</span><span>} +</span><span> +</span><span style="color:#999999;">// Ditto. +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">erasing_cloning_machine2</span><span>&lt;T: </span><span style="color:#c99e00;">Clone </span><span style="color:#3e999f;">+</span><span> Debug&gt;(</span><span style="color:#f5871f;">item</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>T) -&gt; impl Clone </span><span style="color:#3e999f;">+</span><span> Debug { +</span><span> item.</span><span style="color:#4271ae;">clone</span><span>() +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> _opt </span><span style="color:#3e999f;">= </span><span>OurOption::Some(</span><span style="color:#f5871f;">10</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _p1 </span><span style="color:#3e999f;">=</span><span> Tuple2 { x: </span><span style="color:#f5871f;">5</span><span>, y: </span><span style="color:#f5871f;">10 </span><span>}; +</span><span> </span><span style="color:#8959a8;">let</span><span> _p2 </span><span style="color:#3e999f;">= </span><span>Tuple2::new(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2.5</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> arr </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> arr2 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">cloning_machine</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>arr); +</span><span> </span><span style="color:#8959a8;">let</span><span> _x </span><span style="color:#3e999f;">=</span><span> arr2[</span><span style="color:#f5871f;">0</span><span>]; </span><span style="color:#999999;">// This compiles, because `cloning_machine` preserves the type. +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, arr2); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> arr3 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">erasing_cloning_machine1</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>arr); +</span><span> </span><span style="color:#999999;">// arr3[0]; // won&#39;t compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, arr3); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> arr4 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">erasing_cloning_machine2</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>arr); +</span><span> </span><span style="color:#999999;">// arr4[0]; // won&#39;t compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, arr4); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/generics.rs">generics.rs</a>)</sub></p> +<p>A bit more involved example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::fmt::{Display, Formatter}; +</span><span> +</span><span style="color:#8959a8;">trait </span><span>DefaultishablyPrintable&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">defaultish_print</span><span>() +</span><span> </span><span style="color:#8959a8;">where +</span><span> T: Display + Default, +</span><span> { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, T::default()) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Foo; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Bar; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>Bar { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> f.</span><span style="color:#4271ae;">write_str</span><span>(</span><span style="color:#718c00;">&quot;this is a bar&quot;</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Default </span><span style="color:#8959a8;">for </span><span>Bar { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">default</span><span>() -&gt; </span><span style="color:#8959a8;">Self </span><span>{ +</span><span> Bar </span><span style="color:#999999;">// well, we have no other choice +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>DefaultishablyPrintable&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Foo {} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>DefaultishablyPrintable&lt;Bar&gt; </span><span style="color:#8959a8;">for </span><span>Foo {} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#3e999f;">&lt;</span><span>Foo </span><span style="color:#3e999f;">as </span><span>DefaultishablyPrintable&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;</span><span style="color:#3e999f;">&gt;</span><span>::defaultish_print(); +</span><span> &lt;Foo </span><span style="color:#3e999f;">as </span><span>DefaultishablyPrintable&lt;Bar&gt;&gt;::defaultish_print(); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/generics_fun.rs">generics_fun.rs</a>)</sub></p> +<h2 id="static-vs-dynamic-dispatch">Static vs dynamic dispatch</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>Speak { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str</span><span>; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Dog; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Speak </span><span style="color:#8959a8;">for </span><span>Dog { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;Hau hau&quot; </span><span style="color:#999999;">// it&#39;s a Polish dog! +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Human; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Speak </span><span style="color:#8959a8;">for </span><span>Human { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;Hello world&quot; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// It works like templates in C++ +</span><span style="color:#999999;">// A different function will be generated for each T during compilation +</span><span style="color:#999999;">// This process is called &quot;monomorphization&quot; +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">static_dispatch</span><span>&lt;T: Speak&gt;(</span><span style="color:#f5871f;">speaking</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>T) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, speaking.</span><span style="color:#4271ae;">speak</span><span>()); +</span><span>} +</span><span> +</span><span style="color:#999999;">// Only one copy of that function will exist in the compiled binary +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#f5871f;">speaking</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>dyn Speak) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, speaking.</span><span style="color:#4271ae;">speak</span><span>()); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> dog </span><span style="color:#3e999f;">=</span><span> Dog; +</span><span> </span><span style="color:#8959a8;">let</span><span> human </span><span style="color:#3e999f;">=</span><span> Human; +</span><span> +</span><span> </span><span style="color:#4271ae;">static_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>dog); +</span><span> </span><span style="color:#4271ae;">static_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>human); +</span><span> +</span><span> </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>dog); +</span><span> </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>human); +</span><span> +</span><span> </span><span style="color:#999999;">// The observable behavior is identical +</span><span> </span><span style="color:#999999;">// Static dispatch in general is a bit faster, +</span><span> </span><span style="color:#999999;">// because there is no need to perform a &quot;vtable lookup&quot;. +</span><span> </span><span style="color:#999999;">// But it can also result in bigger binary sizes. +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/static_dynamic_dispatch.rs">static_dynamic_dispatch.rs</a>)</sub></p> +<h1 id="lifetimes">Lifetimes</h1> +<p>Going back to the lesson about ownership, if we try to compile the following code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> r; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; +</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); +</span><span>} +</span></code></pre> +<p>we should expect to get an error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0597]: `x` does not live long enough +</span><span> --&gt; src/main.rs:7:17 +</span><span> | +</span><span>7 | r = &amp;x; +</span><span> | ^^ borrowed value does not live long enough +</span><span>8 | } +</span><span> | - `x` dropped here while still borrowed +</span><span>9 | +</span><span>10 | println!(&quot;r: {}&quot;, r); +</span><span> | - borrow later used here +</span></code></pre> +<p>Courtesy of the borrow checker, we didn't end up with a dangling reference. But what exactly is happening behind the scenes? Rust introduces a concept of annotated lifetimes, where the lifetime of each value is being marked and tracked by the checker. Let's look at some examples:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> r; </span><span style="color:#999999;">// ---------+-- &#39;a +</span><span> </span><span style="color:#999999;">// | +</span><span> { </span><span style="color:#999999;">// | +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// -+-- &#39;b | +</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; </span><span style="color:#999999;">// | | +</span><span> } </span><span style="color:#999999;">// -+ | +</span><span> </span><span style="color:#999999;">// | +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); </span><span style="color:#999999;">// | +</span><span>} </span><span style="color:#999999;">// ---------+ +</span></code></pre> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// ----------+-- &#39;b +</span><span> </span><span style="color:#999999;">// | +</span><span> </span><span style="color:#8959a8;">let</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; </span><span style="color:#999999;">// --+-- &#39;a | +</span><span> </span><span style="color:#999999;">// | | +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); </span><span style="color:#999999;">// | | +</span><span> </span><span style="color:#999999;">// --+ | +</span><span>} </span><span style="color:#999999;">// ----------+ +</span></code></pre> +<h2 id="annotations">Annotations</h2> +<p>Let's consider the following code finding the longer out of two strings:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>, </span><span style="color:#f5871f;">y</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> y.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> y +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> string1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;abcd&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> string2 </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;xyz&quot;</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">longest</span><span>(string1.</span><span style="color:#4271ae;">as_str</span><span>(), string2); +</span><span> println!(</span><span style="color:#718c00;">&quot;The longest string is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span></code></pre> +<p>If we try to compile this, we will get an error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0106]: missing lifetime specifier +</span><span> --&gt; src/main.rs:9:33 +</span><span> | +</span><span>9 | fn longest(x: &amp;str, y: &amp;str) -&gt; &amp;str { +</span><span> | ---- ---- ^ expected named lifetime parameter +</span><span> | +</span><span> = help: this function&#39;s return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +</span><span>help: consider introducing a named lifetime parameter +</span><span> | +</span><span>9 | fn longest&lt;&#39;a&gt;(x: &amp;&#39;a str, y: &amp;&#39;a str) -&gt; &amp;&#39;a str { +</span><span> | ++++ ++ ++ ++ +</span></code></pre> +<p>This is because Rust doesn't know which of the two provided strings (<code>x</code> or <code>y</code>) will be returned from the function. And because they potentially have different lifetimes, the lifetime of what we are returning remains unclear to the compiler - it needs our help.</p> +<p>Rust provides syntax for specifying lifetimes. The lifetime parameter name from the example (<code>a</code>) doesn't have any concrete meaning - it's just an arbitrary name for this one lifetime.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">i32 </span><span style="color:#999999;">// a reference +</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a i32 </span><span style="color:#999999;">// a reference with an explicit lifetime +</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a mut i32 </span><span style="color:#999999;">// a mutable reference with an explicit lifetime +</span></code></pre> +<p>So, knowing this, let's address the compiler's demands.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>, </span><span style="color:#f5871f;">y</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> y.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> y +</span><span> } +</span><span>} +</span></code></pre> +<p>When working with lifetimes, our work will usually revolve around specifying relationships between lifetimes of different values so that the compiler can successfully reason about the program's safety. In the context of the example above, this signature means that both of the function's arguments and its output will live at least as long as lifetime <code>'a</code>. In practice, this means that the output's lifetime will be equal to the smaller of the two inputs' lifetimes.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">first</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>, </span><span style="color:#f5871f;">second</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> first.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> second.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> first +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> second +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> string1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;long string is long&quot;</span><span>); +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> string2 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;xyz&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">longest</span><span>(string1.</span><span style="color:#4271ae;">as_str</span><span>(), string2.</span><span style="color:#4271ae;">as_str</span><span>()); +</span><span> println!(</span><span style="color:#718c00;">&quot;The longest string is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// This doesn&#39;t compile - incorrect lifetimes +</span><span> </span><span style="color:#999999;">// +</span><span> </span><span style="color:#999999;">// let string1 = String::from(&quot;long string is long&quot;); +</span><span> </span><span style="color:#999999;">// let result; +</span><span> </span><span style="color:#999999;">// { +</span><span> </span><span style="color:#999999;">// let string2 = String::from(&quot;xyz&quot;); +</span><span> </span><span style="color:#999999;">// result = longest(string1.as_str(), string2.as_str()); +</span><span> </span><span style="color:#999999;">// } +</span><span> </span><span style="color:#999999;">// println!(&quot;The longest string is {}&quot;, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/lifetimes_basic.rs">lifetimes_basic.rs</a>)</sub></p> +<p>Trying to compile the second variant displeases the compiler (just like we hoped).</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0597]: `string2` does not live long enough +</span><span> --&gt; src/main.rs:6:44 +</span><span> | +</span><span>6 | result = longest(string1.as_str(), string2.as_str()); +</span><span> | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough +</span><span>7 | } +</span><span> | - `string2` dropped here while still borrowed +</span><span>8 | println!(&quot;The longest string is {}&quot;, result); +</span><span> | ------ borrow later used here +</span></code></pre> +<h2 id="lifetime-elision">Lifetime elision</h2> +<p>We now know how to explicitly write lifetime parameters, but you might recall that we don't always have to that. Indeed, Rust will first try to figure out the lifetimes itself, applying a set of predefined rules. We call this <em>lifetime elision</em>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span><span> </span><span style="color:#8959a8;">if</span><span> seq.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&lt; </span><span style="color:#f5871f;">2 </span><span>{ +</span><span> seq +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>seq[</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">2</span><span>] +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> seq </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>]; +</span><span> +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;First two elements of the sequence: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, +</span><span> </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>seq[</span><span style="color:#3e999f;">..</span><span>]) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/lifetimes_elision.rs">lifetimes_elision.rs</a>)</sub></p> +<p>The above works, even though we didn't specify any lifetime parameters at all. The reason lies in the rules we mentioned, which are as follows (where input lifetimes are lifetimes on parameters and output lifetimes are lifetimes on return values):</p> +<ul> +<li> +<p>Each parameter that is a reference gets its own lifetime parameter.</p> +</li> +<li> +<p>If there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters.</p> +</li> +<li> +<p>If there are multiple input lifetime parameters, but one of them is <code>&amp;self</code> or <code>&amp;mut self</code>, the lifetime of <code>self</code> is assigned to all output lifetime parameters.</p> +</li> +</ul> +<p>Let's try to understand how the compiler inferred the lifetimes of our <code>first_two</code> functions. We start with the following signature:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>Then, we apply the first rule:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> [</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>Next, we check the second rule. It applies here as well.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> [</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>With that, we arrive at a state where all lifetimes are specified.</p> +<h2 id="static-lifetime">Static lifetime</h2> +<p>There exists one special lifetime called <code>'static</code>, which means that a reference can live for the entire duration of the program. All string literals are annotated with this lifetime as they are stored directly in the program's binary. Full type annotation of a string literal in Rust is therefore as follows:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;I have a static lifetime.&quot;</span><span>; +</span></code></pre> +<h1 id="trait-lifetimes-a-challenging-tandem">Trait + lifetimes - a challenging tandem</h1> +<p>Let's go back to our <code>basic_trait.rs</code> example. The <code>Summary</code> trait was really wasteful: it always allocated the <code>String</code>s on heap, even though we only needed to display the formatted string, and we could do that without allocations. How? By using <code>Display</code> trait, of course.</p> +<p>The simplest possible optimisation would be like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Display; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> write!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location +</span><span> ) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> write!(f, </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.username, </span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/basic_trait_display.rs">basic_trait_display.rs</a>)</sub></p> +<p>This eliminates the heap allocations, but there's another catch. What if <code>NewsArticle</code> already had another (non-summarizing) <code>Display</code> implementation? We would end up in a double-trait-implementation conflict, which is a compile-time error.</p> +<p>We can solve the one-type-one-trait-impl problem by introducing another type just for summarizing. The first attempt could be to use generics in traits:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Display; +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Summary&lt;&#39;a, Summarizer: Display&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; Summarizer; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> writeln!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location +</span><span> )</span><span style="color:#3e999f;">?</span><span>; +</span><span> f.</span><span style="color:#4271ae;">write_str</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> NewsArticle); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticleSummarizer&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> </span><span style="color:#8959a8;">let</span><span> article </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>; +</span><span> write!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> article.headline, article.author, article.location +</span><span> ) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Summary&lt;</span><span style="color:#8959a8;">&#39;a</span><span>, NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;&gt; </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> NewsArticleSummarizer(</span><span style="color:#c82829;">self</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>TweetSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> Tweet); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>TweetSummarizer&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>; +</span><span> write!(f, </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.username, tweet.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Summary&lt;</span><span style="color:#8959a8;">&#39;a</span><span>, TweetSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;&gt; </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; TweetSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> TweetSummarizer(</span><span style="color:#c82829;">self</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Summary&lt;</span><span style="color:#8959a8;">&#39;a</span><span>, NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;&gt; </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> unimplemented!(</span><span style="color:#718c00;">&quot;This is only to make code type-check and compile.&quot;</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> empty_article </span><span style="color:#3e999f;">=</span><span> NewsArticle { +</span><span> headline: </span><span style="color:#718c00;">&quot;&quot;</span><span>.</span><span style="color:#4271ae;">into</span><span>(), +</span><span> location: </span><span style="color:#c99e00;">String</span><span>::new(), +</span><span> author: </span><span style="color:#c99e00;">String</span><span>::default(), +</span><span> content: </span><span style="color:#c99e00;">Default</span><span>::default(), +</span><span> }; +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new article: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, empty_article.</span><span style="color:#4271ae;">summarize</span><span>()); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> </span><span style="color:#999999;">// Compile error: `type annotations needed; multiple `impl`s satisfying `Tweet: Summary&lt;&#39;_, _&gt;` found` +</span><span> </span><span style="color:#999999;">// println!(&quot;1 new tweet: {}&quot;, tweet.summarize()); +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, +</span><span> &lt;Tweet </span><span style="color:#3e999f;">as </span><span>Summary&lt;&#39;</span><span style="color:#3e999f;">_</span><span>, TweetSummarizer&gt;&gt;::summarize(</span><span style="color:#3e999f;">&amp;</span><span>tweet) +</span><span> ); +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, +</span><span> &lt;Tweet </span><span style="color:#3e999f;">as </span><span>Summary&lt;&#39;</span><span style="color:#3e999f;">_</span><span>, NewsArticleSummarizer&gt;&gt;::summarize(</span><span style="color:#3e999f;">&amp;</span><span>tweet) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/trait_generic_type.rs">trait_generic_type.rs</a>)</sub></p> +<p>The problem here is that nothing hinders us from implement the trait (with various type parameters) for the same type, which leads to awkward ambiguity when calling the trait's methods (see <code>main</code> fn).</p> +<p>The use of generic types in <code>Summary</code> trait makes it semantics like this:</p> +<blockquote> +<p>A type can be summarized with any type supporting it.</p> +</blockquote> +<p>When we want the trait to require exactly one possible generic implementation for a given type, we can leverage <em>associated types</em>. Example here:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Display; +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Summary&lt;&#39;a&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Summarizer: Display; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Summarizer; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> writeln!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location +</span><span> )</span><span style="color:#3e999f;">?</span><span>; +</span><span> f.</span><span style="color:#4271ae;">write_str</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> NewsArticle); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticleSummarizer&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> </span><span style="color:#8959a8;">let</span><span> article </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>; +</span><span> write!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> article.headline, article.author, article.location +</span><span> ) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Summary&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">type </span><span>Summarizer </span><span style="color:#3e999f;">= </span><span>NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Summarizer { +</span><span> NewsArticleSummarizer(</span><span style="color:#c82829;">self</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>TweetSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> Tweet); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>TweetSummarizer&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>; +</span><span> write!(f, </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.username, tweet.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Summary&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">type </span><span>Summarizer </span><span style="color:#3e999f;">= </span><span>TweetSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Summarizer { +</span><span> TweetSummarizer(</span><span style="color:#c82829;">self</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.</span><span style="color:#4271ae;">summarize</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/trait_associated_type.rs">trait_associated_type.rs</a>)</sub></p> +<p>The use of associated types in Summary trait makes it semantics like this:</p> +<blockquote> +<p>A type can be summarized with at most one specific type.</p> +</blockquote> +<p>Yet another approach (arguably, the cleanest one) would be to use the <code>impl trait</code> syntax in a trait (quite recently stabilized!). +Example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Display; +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Summary { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; impl Display; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> writeln!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location +</span><span> )</span><span style="color:#3e999f;">?</span><span>; +</span><span> f.</span><span style="color:#4271ae;">write_str</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticleSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> NewsArticle); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>NewsArticleSummarizer&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> </span><span style="color:#8959a8;">let</span><span> article </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>; +</span><span> write!( +</span><span> f, +</span><span> </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, +</span><span> article.headline, article.author, article.location +</span><span> ) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; impl Display { +</span><span> NewsArticleSummarizer(</span><span style="color:#c82829;">self</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; impl Display { +</span><span> </span><span style="color:#8959a8;">struct </span><span>TweetSummarizer&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> Tweet); +</span><span> +</span><span> </span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>TweetSummarizer&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>std::fmt::Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>; +</span><span> write!(f, </span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.username, tweet.content) +</span><span> } +</span><span> } +</span><span> +</span><span> TweetSummarizer(</span><span style="color:#c82829;">self</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.</span><span style="color:#4271ae;">summarize</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/05-types-reasoning/impl_trait.rs">impl_trait.rs</a>)</sub></p> +<h1 id="obligatory-reading">Obligatory reading</h1> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch10-00-generics.html">The Book, chapter 10</a></p> +</li> +<li> +<p><a href="https://oswalt.dev/2021/06/polymorphism-in-rust/">Polymorphism in Rust</a></p> +</li> +</ul> +<h2 id="assignment-3-graded">Assignment 3 (graded)</h2> +<p><a href="https://classroom.github.com/a/VTyPdlC2">Passage Pathing</a></p> +<p>Deadline: 30.10.2024 23:59</p> + + + + + Data Types + 2024-10-17T00:00:00+00:00 + 2024-10-17T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/03-data-types/ + + <h2 id="aggregating-data">Aggregating data</h2> +<p>Below is a compact overview of Rust's structs</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#[</span><span style="color:#c82829;">derive</span><span>(Clone, Copy, Debug, Eq, PartialEq)] +</span><span style="color:#8959a8;">struct </span><span>Position(</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#8959a8;">i32</span><span>); </span><span style="color:#999999;">// tuple struct +</span><span> +</span><span style="color:#999999;">// Could Hero derive the Copy trait? +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Clone, Debug, Eq, PartialEq)] +</span><span style="color:#8959a8;">struct </span><span>Hero { +</span><span> </span><span style="color:#c82829;">name</span><span>: String, +</span><span> </span><span style="color:#c82829;">level</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">experience</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">position</span><span>: Position, +</span><span>} +</span><span> +</span><span style="color:#999999;">// we can add methods to structs using the &#39;impl&#39; keyword +</span><span style="color:#8959a8;">impl </span><span>Hero { +</span><span> </span><span style="color:#999999;">// static method (in Rust nomenclature: &quot;associated function&quot;) +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">name</span><span>: String) -&gt; Hero { +</span><span> Hero { +</span><span> name, +</span><span> level: </span><span style="color:#f5871f;">1</span><span>, +</span><span> experience: </span><span style="color:#f5871f;">0</span><span>, +</span><span> position: Position(</span><span style="color:#f5871f;">0</span><span>, </span><span style="color:#f5871f;">0</span><span>), +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// multiple impl blocks are possible for one struct +</span><span style="color:#8959a8;">impl </span><span>Hero { +</span><span> </span><span style="color:#999999;">// instance method, first argument (self) is the calling instance +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">distance</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">pos</span><span>: Position) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#999999;">// shorthand to: `self: &amp;Self` +</span><span> </span><span style="color:#999999;">// field `i` of a tuple or a tuple struct can be accessed through &#39;tuple.i&#39; +</span><span> (pos.</span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">- </span><span style="color:#c82829;">self</span><span>.position.</span><span style="color:#f5871f;">0</span><span>).</span><span style="color:#4271ae;">unsigned_abs</span><span>() </span><span style="color:#3e999f;">+ </span><span>(pos.</span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">- </span><span style="color:#c82829;">self</span><span>.position.</span><span style="color:#f5871f;">1</span><span>).</span><span style="color:#4271ae;">unsigned_abs</span><span>() +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// mutable borrow of self allows to change instance fields +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">level_up</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#999999;">// shorthand to: `self: &amp;mut Self` +</span><span> </span><span style="color:#c82829;">self</span><span>.experience </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#c82829;">self</span><span>.level </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// &#39;self&#39; is not borrowed here and will be moved into the method +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">die</span><span>(</span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#999999;">// shorthand to: `self: Self` +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Here lies </span><span style="color:#666969;">{}</span><span style="color:#718c00;">, a hero who reached level </span><span style="color:#666969;">{}</span><span style="color:#718c00;">. RIP.&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.name, </span><span style="color:#c82829;">self</span><span>.level +</span><span> ); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// Calling associated functions requires scope (`::`) operator. +</span><span> </span><span style="color:#8959a8;">let mut</span><span> hero: Hero </span><span style="color:#3e999f;">= </span><span>Hero::new(</span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Ferris&quot;</span><span>)); +</span><span> hero.</span><span style="color:#4271ae;">level_up</span><span>(); </span><span style="color:#999999;">// &#39;self&#39; is always passed implicitly +</span><span> +</span><span> </span><span style="color:#999999;">// fields other than &#39;name&#39; will be the same as in &#39;hero&#39; +</span><span> </span><span style="color:#8959a8;">let</span><span> steve </span><span style="color:#3e999f;">=</span><span> Hero { +</span><span> name: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Steve The Normal Guy&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">..</span><span>hero +</span><span> }; +</span><span> +</span><span> assert_eq!(hero.level, steve.level); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> twin </span><span style="color:#3e999f;">=</span><span> hero.</span><span style="color:#4271ae;">clone</span><span>(); +</span><span> +</span><span> </span><span style="color:#999999;">// we can compare Hero objects because it derives the PartialEq trait +</span><span> assert_eq!(hero, twin); +</span><span> twin.</span><span style="color:#4271ae;">level_up</span><span>(); +</span><span> assert_ne!(hero, twin); +</span><span> hero.</span><span style="color:#4271ae;">level_up</span><span>(); +</span><span> assert_eq!(hero, twin); +</span><span> +</span><span> </span><span style="color:#999999;">// we can print out a the struct&#39;s debug string with &#39;{:?}&#39; +</span><span> println!(</span><span style="color:#718c00;">&quot;print to stdout: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, hero); +</span><span> +</span><span> hero.</span><span style="color:#4271ae;">die</span><span>(); </span><span style="color:#999999;">// &#39;hero&#39; is not usable after this invocation, see the method&#39;s definiton +</span><span> +</span><span> </span><span style="color:#999999;">// the dbg! macro prints debug strings to stderr along with file and line number +</span><span> </span><span style="color:#999999;">// dbg! takes its arguments by value, so better borrow them not to have them +</span><span> </span><span style="color:#999999;">// moved into dbg! and consumed. +</span><span> dbg!(</span><span style="color:#718c00;">&quot;print to stderr: {}&quot;</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>twin); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> pos </span><span style="color:#3e999f;">=</span><span> Position(</span><span style="color:#f5871f;">42</span><span>, </span><span style="color:#f5871f;">0</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> dist </span><span style="color:#3e999f;">=</span><span> steve.</span><span style="color:#4271ae;">distance</span><span>(pos); </span><span style="color:#999999;">// no clone here as Position derives the Copy trait +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, pos); +</span><span> assert_eq!(dist, </span><span style="color:#f5871f;">42</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/data_types.rs">data_types.rs</a>)</sub></p> +<h2 id="enums">Enums</h2> +<p>It is often the case that we want to define a variable that can only take +a certain set of values and the values are known up front. In C you can use an <code>enum</code> for this.</p> +<pre data-lang="c" style="background-color:#ffffff;color:#4d4d4c;" class="language-c "><code class="language-c" data-lang="c"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;stdio.h&gt; +</span><span> +</span><span style="color:#8959a8;">enum </span><span>shirt_size { +</span><span> small, +</span><span> medium, +</span><span> large, +</span><span> xlarge +</span><span>}; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_size</span><span>(</span><span style="color:#8959a8;">enum</span><span> shirt_size </span><span style="color:#f5871f;">size</span><span>) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;my size is &quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">switch </span><span>(size) { +</span><span> </span><span style="color:#8959a8;">case</span><span> small: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;small&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> medium: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;medium&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> large: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;large&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> xlarge: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;xlarge&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">default</span><span>: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;unknown&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">enum</span><span> shirt_size my_size </span><span style="color:#3e999f;">=</span><span> medium; +</span><span> </span><span style="color:#c82829;">print_size</span><span style="color:#4271ae;">(my_size)</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/enums.c">enums.c</a>)</sub></p> +<p>However, in C enums are just integers. Nothing prevents us from writing</p> +<pre data-lang="c" style="background-color:#ffffff;color:#4d4d4c;" class="language-c "><code class="language-c" data-lang="c"><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">enum</span><span> shirt_size my_size </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">666</span><span>; +</span><span> </span><span style="color:#c82829;">print_size</span><span style="color:#4271ae;">(my_size)</span><span>; +</span><span>} +</span></code></pre> +<p>C++ introduces enum classes which are type-safe. Legacy enums are also somewhat safer than in C (same code as above):</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>&lt;source&gt;:27:31: error: invalid conversion from &#39;int&#39; to &#39;shirt_size&#39; [-fpermissive] +</span><span> 27 | enum shirt_size my_size = 666; +</span><span> | ^~~ +</span><span> | | +</span><span> | int +</span></code></pre> +<p>Some programming languages (especially functional ones) allow programmers to define +enums which carry additional information. Such types are usually called <code>tagged unions</code> +or <code>algebraic data types</code>.</p> +<p>In C++ we can use <code>union</code> with an <code>enum</code> tag to define it:</p> +<pre data-lang="cpp" style="background-color:#ffffff;color:#4d4d4c;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;iostream&gt; +</span><span> +</span><span style="color:#999999;">// Taken from: https://en.cppreference.com/w/cpp/language/union +</span><span> +</span><span style="color:#999999;">// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), +</span><span style="color:#999999;">// and three variant members (c, i, d) +</span><span style="color:#8959a8;">struct </span><span>S +</span><span>{ +</span><span> </span><span style="color:#8959a8;">enum</span><span>{</span><span style="color:#c99e00;">CHAR</span><span>, </span><span style="color:#c99e00;">INT</span><span>, DOUBLE} tag; +</span><span> </span><span style="color:#8959a8;">union +</span><span> { +</span><span> </span><span style="color:#8959a8;">char</span><span> c; +</span><span> </span><span style="color:#8959a8;">int</span><span> i; +</span><span> </span><span style="color:#8959a8;">double</span><span> d; +</span><span> }; +</span><span>}; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_s</span><span>(</span><span style="color:#8959a8;">const</span><span> S</span><span style="color:#3e999f;">&amp; </span><span style="color:#f5871f;">s</span><span>) +</span><span>{ +</span><span> </span><span style="color:#8959a8;">switch</span><span>(s.</span><span style="color:#c82829;">tag</span><span>) +</span><span> { +</span><span> </span><span style="color:#8959a8;">case</span><span> S::</span><span style="color:#c99e00;">CHAR</span><span>: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">c </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> S::</span><span style="color:#c99e00;">INT</span><span>: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">i </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> S::DOUBLE: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">d </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() +</span><span>{ +</span><span> S s </span><span style="color:#3e999f;">= </span><span>{S::</span><span style="color:#c99e00;">CHAR</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>}; +</span><span> </span><span style="color:#c82829;">print_s</span><span style="color:#4271ae;">(s)</span><span>; +</span><span> s.</span><span style="color:#c82829;">tag </span><span style="color:#3e999f;">=</span><span> S::</span><span style="color:#c99e00;">INT</span><span>; +</span><span> s.</span><span style="color:#c82829;">i </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">123</span><span>; +</span><span> </span><span style="color:#c82829;">print_s</span><span style="color:#4271ae;">(s)</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/tagged_union.cpp">tagged_union.cpp</a>)</sub></p> +<p>C++17 introduced a new feature called <code>variant</code> which generalizes this concept. +You can read more about it <a href="https://en.cppreference.com/w/cpp/utility/variant">here</a>.</p> +<p>Java has a more or less analogous feature called <code>sealed classes</code> +since <a href="https://docs.oracle.com/en/java/javase/17/language/sealed-classes-and-interfaces.html.">version 17</a>.</p> +<h2 id="enums-in-rust">Enums in Rust</h2> +<p>Let's see how they are defined in Rust.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span style="color:#8959a8;">enum </span><span>NamedSize { +</span><span> Small, +</span><span> Medium, +</span><span> Large, +</span><span> </span><span style="color:#666969;">XL</span><span>, +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span style="color:#8959a8;">enum </span><span>ShirtSize { +</span><span> Named(NamedSize), +</span><span> Numeric(</span><span style="color:#8959a8;">u32</span><span>), +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Isn&#39;t it strange that some clothes&#39; sizes are adjectives like </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">,&quot;</span><span>, +</span><span> ShirtSize::Named(NamedSize::Small) +</span><span> ); +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;but sometimes they are numbers like </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">?&quot;</span><span>, +</span><span> ShirtSize::Numeric(</span><span style="color:#f5871f;">42</span><span>) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/enums.rs">enums.rs</a>)</sub></p> +<p>In Rust, enums are a core feature of the language. +You may have heard that one of Rust's defining characteristics is +the absence of <a href="https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions">&quot;the billion dollar mistake&quot;</a>. +So what can we do to say that a value is missing if there is no <code>null</code>?</p> +<p>In Rust, we can use the <code>Option</code> type to represent the absence of a value.</p> +<p>Option is defined as:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">enum </span><span>Option&lt;T&gt; { +</span><span> </span><span style="color:#c99e00;">Some</span><span>(T), +</span><span> </span><span style="color:#c99e00;">None</span><span>, +</span><span>} +</span></code></pre> +<p>The <code>&lt;T&gt;</code> part is called the &quot;type parameter&quot; and it causes Option to be generic. +We won't go deeper into this for now.</p> +<p>The fact that variables which could be <code>null</code> in other languages have a different type in Rust is +the solution to the billion dollar mistake!</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> not_null: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> not_null </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">43</span><span>; +</span><span> </span><span style="color:#999999;">// not_null = None; // this won&#39;t compile because it&#39;s a different type! +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> nullable: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">43</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// such construction is rare, but possible +</span><span> </span><span style="color:#8959a8;">let mut</span><span> double_nullable: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> </span><span style="color:#999999;">// assert_ne!(double_nullable, Some(42)); // this won&#39;t even compile because it&#39;s a different type! +</span><span> double_nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> double_nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// None and Some(None) are different! +</span><span> assert_ne!(double_nullable, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// Now recall that division by 0 *panics* +</span><span> </span><span style="color:#999999;">// A panic is an unrecoverable error +</span><span> </span><span style="color:#999999;">// It is not an exception! +</span><span> </span><span style="color:#999999;">// And in Rust there are no exceptions, so there are no try/catch blocks +</span><span> </span><span style="color:#999999;">// Now let&#39;s imagine that we want to divide one number by another +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">divide</span><span>(</span><span style="color:#f5871f;">dividend</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">divisor</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> dividend </span><span style="color:#3e999f;">/</span><span> divisor +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We get the divisor from the user, so it can be 0 +</span><span> </span><span style="color:#999999;">// We want to handle this situation gracefully - we don&#39;t want to crash the program! +</span><span> </span><span style="color:#999999;">// We can do this by using the Option&lt;T&gt; type +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">safe_divide</span><span>(</span><span style="color:#f5871f;">dividend</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">divisor</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">if</span><span> divisor </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#c99e00;">None +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c99e00;">Some</span><span>(dividend </span><span style="color:#3e999f;">/</span><span> divisor) +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Fortunately, such a function is already included in the standard library +</span><span> </span><span style="color:#8959a8;">let</span><span> number: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> </span><span style="color:#999999;">// We need to specify the type explicitly +</span><span> </span><span style="color:#999999;">// because checked_div is implemented for all integer types +</span><span> </span><span style="color:#999999;">// and Rust won&#39;t know which type we want to use +</span><span> assert_eq!(number.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">2</span><span>), </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">21</span><span>)); +</span><span> assert_eq!(number.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">0</span><span>), </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// Now let&#39;s imagine we search for a value in an array. +</span><span> </span><span style="color:#8959a8;">let</span><span> numbers </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>, </span><span style="color:#f5871f;">5</span><span>]; +</span><span> </span><span style="color:#8959a8;">let</span><span> three </span><span style="color:#3e999f;">=</span><span> numbers.</span><span style="color:#4271ae;">iter</span><span>().</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">find</span><span>(|</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">3</span><span>); +</span><span> assert_eq!(three, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> </span><span style="color:#8959a8;">let</span><span> seven </span><span style="color:#3e999f;">=</span><span> numbers.</span><span style="color:#4271ae;">iter</span><span>().</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">find</span><span>(|</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">7</span><span>); +</span><span> assert_eq!(seven, </span><span style="color:#c99e00;">None</span><span>); +</span><span> </span><span style="color:#999999;">// We won&#39;t delve deeper into the details of how iterators work for now, +</span><span> </span><span style="color:#999999;">// but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust +</span><span> +</span><span> </span><span style="color:#999999;">// Usually there are two kinds of methods: +</span><span> </span><span style="color:#999999;">// ones that will panic if the argument is incorrect, +</span><span> </span><span style="color:#999999;">// numbers[8]; // this will panic! +</span><span> </span><span style="color:#999999;">// and `checked` ones that return an Option +</span><span> assert_eq!(numbers.</span><span style="color:#4271ae;">get</span><span>(</span><span style="color:#f5871f;">8</span><span>), </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// We can use `unwrap` to get the value out of an Option +</span><span> </span><span style="color:#999999;">// but we must be absolutely sure that the Option is Some, otherwise we&#39;ll get a panic +</span><span> </span><span style="color:#999999;">// numbers.get(8).unwrap(); // this will panic! +</span><span> assert_eq!(numbers.</span><span style="color:#4271ae;">get</span><span>(</span><span style="color:#f5871f;">8</span><span>).</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">unwrap_or</span><span>(</span><span style="color:#f5871f;">0</span><span>), </span><span style="color:#f5871f;">0</span><span>); </span><span style="color:#999999;">// or we can provide a default value +</span><span> +</span><span> </span><span style="color:#999999;">// Usually instead of unwrapping we use pattern matching, we&#39;ll get to this in a minute +</span><span> </span><span style="color:#999999;">// but first let&#39;s see what else we can do with an option +</span><span> </span><span style="color:#8959a8;">let</span><span> number: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> </span><span style="color:#999999;">// We can use `map` to transform the value inside an Option +</span><span> </span><span style="color:#8959a8;">let</span><span> doubled </span><span style="color:#3e999f;">=</span><span> number.</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>); +</span><span> assert_eq!(doubled, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">84</span><span>)); +</span><span> </span><span style="color:#999999;">// We can use flatten to reduce one level of nesting +</span><span> </span><span style="color:#8959a8;">let</span><span> nested </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> assert_eq!(nested.</span><span style="color:#4271ae;">flatten</span><span>(), </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> </span><span style="color:#999999;">// We can use `and_then` to chain multiple options +</span><span> </span><span style="color:#999999;">// This operation is called `flatmap` in some languages +</span><span> </span><span style="color:#8959a8;">let</span><span> chained </span><span style="color:#3e999f;">=</span><span> number +</span><span> .</span><span style="color:#4271ae;">and_then</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">0</span><span>)) +</span><span> .</span><span style="color:#4271ae;">and_then</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> assert_eq!(chained, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// The last two things we&#39;ll cover here are `take` and `replace` +</span><span> </span><span style="color:#999999;">// They are important when dealing with non-Copy types +</span><span> </span><span style="color:#999999;">// `take` will return the value inside an Option and leave a None in its place +</span><span> </span><span style="color:#8959a8;">let mut</span><span> option: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> </span><span style="color:#999999;">// Again, we need to specify the type +</span><span> </span><span style="color:#999999;">// Even though we want to say that there is no value inside the Option, +</span><span> </span><span style="color:#999999;">// this absent value must have a concrete type! +</span><span> assert_eq!(option.</span><span style="color:#4271ae;">take</span><span>(), </span><span style="color:#c99e00;">None</span><span>); +</span><span> assert_eq!(option, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> y </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">None</span><span>); +</span><span> assert_eq!(y, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// `replace` can be used to swap the value inside an Option +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> old </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> assert_eq!(old, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> old </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#f5871f;">3</span><span>); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> assert_eq!(old, </span><span style="color:#c99e00;">None</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/option.rs">option.rs</a>)</sub></p> +<h2 id="pattern-matching">Pattern matching</h2> +<p>Pattern matching is a powerful feature of Rust and many functional languages, but it's slowly making +its way into imperative languages like Java and Python as well.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// Pattern matching is basically a switch on steroids. +</span><span> </span><span style="color:#8959a8;">let</span><span> number </span><span style="color:#3e999f;">= </span><span>rand::random::&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;(); +</span><span> </span><span style="color:#8959a8;">match</span><span> number </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">7 </span><span>{ +</span><span> </span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is divisible by 7&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is *almost* divisible by 7&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is not divisible by 7&quot;</span><span>), +</span><span> } +</span><span> +</span><span> #[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span> </span><span style="color:#8959a8;">enum </span><span>Color { +</span><span> Pink, +</span><span> Brown, +</span><span> Lime, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> color </span><span style="color:#3e999f;">= </span><span>Color::Lime; +</span><span> </span><span style="color:#8959a8;">match</span><span> color { +</span><span> Color::Pink </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not my favorite color!&quot;</span><span>), </span><span style="color:#999999;">// _ is a wildcard +</span><span> </span><span style="color:#999999;">// Rust will statically check that we covered all cases or included a default case. +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can also use pattern matching to match on multiple values. +</span><span> </span><span style="color:#8959a8;">match </span><span>(color, number </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">7</span><span>) { +</span><span> (Color::Pink, </span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color and number!&quot;</span><span>), +</span><span> (Color::Pink, </span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color!&quot;</span><span>), +</span><span> (</span><span style="color:#3e999f;">_</span><span>, </span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite number!&quot;</span><span>), +</span><span> (</span><span style="color:#3e999f;">_</span><span>, </span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not my favorite color or number!&quot;</span><span>), +</span><span> } +</span><span> </span><span style="color:#999999;">// (This is not special syntax, we&#39;re just pattern matching tuples.) +</span><span> +</span><span> </span><span style="color:#999999;">// But we can also *destructure* the value +</span><span> </span><span style="color:#8959a8;">struct </span><span>Human { +</span><span> </span><span style="color:#c82829;">age</span><span>: </span><span style="color:#8959a8;">u8</span><span>, +</span><span> </span><span style="color:#c82829;">favorite_color</span><span>: Color, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> john </span><span style="color:#3e999f;">=</span><span> Human { +</span><span> age: </span><span style="color:#f5871f;">42</span><span>, +</span><span> favorite_color: Color::Pink, +</span><span> }; +</span><span> +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#3e999f;">&amp;</span><span>john { +</span><span> Human { +</span><span> age: </span><span style="color:#f5871f;">42</span><span>, +</span><span> favorite_color: Color::Pink, +</span><span> } </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Okay, that&#39;s John!&quot;</span><span>), +</span><span> Human { +</span><span> favorite_color: Color::Pink, +</span><span> </span><span style="color:#3e999f;">.. +</span><span> } </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not John, but still his favorite color!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Somebody else?&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Note two things: +</span><span> </span><span style="color:#999999;">// 1. Color is *not* Eq, so we can&#39;t use == to compare it, but pattern matching is fine. +</span><span> </span><span style="color:#999999;">// 2. We *borrowed* the value, so we can use it after the match. +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;John is </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> years old and still kicking!&quot;</span><span>, john.age); +</span><span> +</span><span> </span><span style="color:#999999;">// To save some time, we can use `if let` to match against only one thing +</span><span> </span><span style="color:#999999;">// We could also use `while let ... {}` in the same way +</span><span> </span><span style="color:#8959a8;">if let </span><span>Color::Pink </span><span style="color:#3e999f;">= &amp;</span><span>john.favorite_color { +</span><span> println!(</span><span style="color:#718c00;">&quot;He&#39;s also a man of great taste&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can match ranges... +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">12 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a kid!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">13</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a teenager!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">20</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">29 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a young adult!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">30</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">49 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an adult!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">50</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">69 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is mature!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is old!&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use match and capture the value at the same time. +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">12 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a kid, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">13</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a teenager, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">20</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">29 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a young adult, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">30</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">49 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an adult, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">50</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">69 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is mature, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is old, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use guards to check for multiple conditions. +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">12</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#8959a8;">if</span><span> age </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an *odd* teenager, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#8959a8;">if</span><span> age </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an *even* man, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is normal&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Finally, let&#39;s look at some references now +</span><span> </span><span style="color:#8959a8;">let</span><span> reference: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= &amp;</span><span style="color:#f5871f;">4</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">match</span><span> reference { +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>val </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Value under reference is: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, val), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// `ref` can be used to create a reference when destructuring +</span><span> </span><span style="color:#8959a8;">let</span><span> Human { +</span><span> age, +</span><span> </span><span style="color:#8959a8;">ref</span><span> favorite_color, +</span><span> } </span><span style="color:#3e999f;">=</span><span> john; +</span><span> </span><span style="color:#999999;">// `john` is still valid, because we borrowed using `ref` +</span><span> </span><span style="color:#8959a8;">if let </span><span>Color::Pink </span><span style="color:#3e999f;">= &amp;</span><span>john.favorite_color { +</span><span> println!(</span><span style="color:#718c00;">&quot;John still has his color - </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">!&quot;</span><span>, favorite_color); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> john </span><span style="color:#3e999f;">=</span><span> john; +</span><span> +</span><span> </span><span style="color:#999999;">// `ref mut` borrows mutably +</span><span> </span><span style="color:#8959a8;">let</span><span> Human { +</span><span> age, +</span><span> </span><span style="color:#8959a8;">ref mut</span><span> favorite_color, +</span><span> } </span><span style="color:#3e999f;">=</span><span> john; +</span><span> </span><span style="color:#999999;">// We use `*` to dereference +</span><span> </span><span style="color:#3e999f;">*</span><span>favorite_color </span><span style="color:#3e999f;">= </span><span>Color::Brown; +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Tastes do change with time and John likes </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;"> now.&quot;</span><span>, +</span><span> john.favorite_color +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/pattern_matching.rs">pattern_matching.rs</a>)</sub></p> +<h2 id="result">Result</h2> +<p>We said there are no exceptions in Rust and panics mean errors which cannot be caught. +So how do we handle situations which can fail? That's where the <code>Result</code> type comes in.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fs::File; +</span><span style="color:#8959a8;">use </span><span>std::io; +</span><span style="color:#8959a8;">use </span><span>std::io::Read; +</span><span> +</span><span style="color:#999999;">// Let&#39;s try reading from a file. +</span><span style="color:#999999;">// Obviously this can fail. +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_try</span><span>() -&gt; io::</span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">let</span><span> file </span><span style="color:#3e999f;">= </span><span>File::open(</span><span style="color:#718c00;">&quot;/dev/random&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">match</span><span> file { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#8959a8;">mut</span><span> file) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#999999;">// We got a file! +</span><span> </span><span style="color:#8959a8;">let mut</span><span> buffer </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#f5871f;">128</span><span>]; +</span><span> </span><span style="color:#999999;">// Matching each result quickly become tedious... +</span><span> </span><span style="color:#8959a8;">match</span><span> file.</span><span style="color:#4271ae;">read_exact</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> buffer) { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> gibberish </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from_utf8_lossy(</span><span style="color:#3e999f;">&amp;</span><span>buffer); +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish.</span><span style="color:#4271ae;">to_string</span><span>()) +</span><span> } +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c99e00;">Err</span><span>(error), +</span><span> } +</span><span> } +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#999999;">// This is needed in order to change the type from `io::Result&lt;File&gt;` to `io::Result&lt;()&gt;` +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// The &#39;?&#39; operator allows us to return early in case of an error +</span><span style="color:#999999;">// (it automatically converts the error type) +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">second_try</span><span>(</span><span style="color:#f5871f;">filename</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str</span><span>) -&gt; io::</span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> file </span><span style="color:#3e999f;">= </span><span>File::open(filename)</span><span style="color:#3e999f;">?</span><span>; +</span><span> </span><span style="color:#8959a8;">let mut</span><span> buffer </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#f5871f;">128</span><span>]; +</span><span> file.</span><span style="color:#4271ae;">read_exact</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> buffer)</span><span style="color:#3e999f;">?</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> gibberish </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from_utf8_lossy(</span><span style="color:#3e999f;">&amp;</span><span>buffer); +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish.</span><span style="color:#4271ae;">to_string</span><span>()) +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> filenames </span><span style="color:#3e999f;">= </span><span>[ +</span><span> </span><span style="color:#718c00;">&quot;/dev/random&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/null&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/cpu&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/fuse&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;there_certainly_is_no_such_file&quot;</span><span>, +</span><span> ]; +</span><span> </span><span style="color:#8959a8;">for</span><span> filename </span><span style="color:#3e999f;">in</span><span> filenames { +</span><span> println!(</span><span style="color:#718c00;">&quot;Trying to read from &#39;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&#39;&quot;</span><span>, filename); +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#4271ae;">second_try</span><span>(filename) { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, gibberish), +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Error: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, error), +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/03-data-types/result.rs">result.rs</a>)</sub></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li>The Book, chapters <a href="https://doc.rust-lang.org/book/ch05-00-structs.html">5</a>, +<a href="https://doc.rust-lang.org/stable/book/ch06-00-enums.html">6</a>, +<a href="https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html">8</a> +and <a href="https://doc.rust-lang.org/stable/book/ch09-00-error-handling.html">9</a></li> +<li><a href="https://doc.rust-lang.org/std/option/">Option docs</a></li> +<li><a href="https://doc.rust-lang.org/std/result/">Result docs</a></li> +</ul> +<h2 id="assignment-2-graded">Assignment 2 (graded)</h2> +<p><a href="https://classroom.github.com/a/gDraT0lo">Communications</a></p> +<p>Deadline: 23.10.2024 23:59</p> + + + + + Ownership Model + 2024-10-08T00:00:00+00:00 + 2024-10-08T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/02-ownership/ + + <h2 id="why-all-the-fuss">Why all the fuss?</h2> +<p>Even if you've never seen Rust code before, chances are you still heard the term <em>borrow checker</em> or something about Rust's ownership. Indeed, Rust's ownership model lies at the very core of its uniqueness. But to fully understand it and appreciate it, let's first take a look at how memory management is handled in most popular languages.</p> +<ul> +<li> +<p><strong>Garbage Collection</strong> - in many high-level programming languages, like Java, Haskell or Python, memory management is done fully by the language, relieving the programmer from this burden. This prevents memory leaks and memory related errors (like <em>use after free</em>), but does come at a cost - there is a runtime overhead, both memory and performance wise, caused by the constantly running garbage collection algorithms and the programmer usually has very little control over when the garbage collection takes place. Also, garbage collection does not prevent concurrency-related errors, such as data races, in any way.</p> +</li> +<li> +<p><strong>Mind your own memory</strong> - in low-level languages and specific ones like C++, performance comes first so we cannot really afford to run expansive bookkeeping and cleaning algorithms. Most of these languages compile directly to machine code and have no language-specific runtime environment. That means that the only place where memory management can happen is in the produced code. While compilers insert these construction and destruction calls for stack allocated memory, it generally requires a lot of discipline from the programmer to adhere to good practices and patterns to avoid as many memory related issues as possible and one such bug can be quite deadly to the program and a nightmare to find and fix. These languages basically live by the <em>&quot;your memory, your problem&quot;</em> mantra.</p> +</li> +</ul> +<p>And then we have Rust. Rust is a systems programming language and in many ways it's akin to C++ - it's basically low-level with many high-level additions. But unlike C++, it doesn't exactly fall into either of the categories described above, though it's way closer to the second one. It performs no additional management at runtime, but instead imposes a set of rules on the code, making it easier to reason about and thus check for its safety and correctness at compile time - these rules make up Rust's <strong>ownership model</strong>.</p> +<p>In a way, programming in Rust is like pair-programming with a patient and very experienced partner. Rust's compiler will make sure you follow all the good patterns and practices (by having them ingrained in the language itself) and very often even tell you how to fix the issues it finds.</p> +<p><em><strong>Disclaimer:</strong> when delving deeper into Rust below we will make heavy use of concepts like scopes, moving data, stack and heap, which should have been introduced as part of the C++ course. If you need a refresher of any of these, it's best to do so now, before reading further.</em></p> +<h2 id="start-with-the-basics-ownership">Start with the basics - ownership</h2> +<p>In the paragraph above we mentioned a set of rules that comprise Rust's ownership model. <a href="https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ownership-rules">The book</a> starts off with the following three as its very foundation:</p> +<ol> +<li> +<p>Each value in Rust is tied to a specific variable - we call that variable its <strong>owner</strong>.</p> +</li> +<li> +<p>There can only be one owner at a time.</p> +</li> +<li> +<p>When the owner goes out of scope, the value will be destroyed (or in Rust terms - <em>dropped</em>).</p> +</li> +</ol> +<p>The third point might make you think about C++ and its automatic storage duration. We will later see that, while very similar at first, Rust expands on these mechanics quite a bit. The following code illustrates the basic version of this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> a: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// allocation on the stack, &#39;a&#39; becomes an owner +</span><span> +</span><span> </span><span style="color:#999999;">// do some stuff with &#39;a&#39; +</span><span> +</span><span>} </span><span style="color:#999999;">// &#39;a&#39;, the owner, goes out of scope and the value is dropped +</span></code></pre> +<p>So far, so good. Variables are pushed onto the stack when they enter the scope and destroyed during stack unwinding that happens upon leaving their scope. However, allocating and deallocating simple integers doesn't impress anybody. Let's try something more complex:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// &#39;s&#39; is allocated on the stack, while its contents (&quot;a string&quot;) +</span><span> </span><span style="color:#999999;">// are allocated on the heap. &#39;s&#39; is the owner of this String object. +</span><span> +</span><span> </span><span style="color:#999999;">// do some stuff with &#39;s&#39; +</span><span> +</span><span>} </span><span style="color:#999999;">// &#39;s&#39;, the owner, goes out of scope and the String is dropped, its heap allocated memory freed +</span></code></pre> +<p>If you recall the RAII (Resource Acquisition Is Initialization) pattern from C++, the above is basically the same thing. We go two for two now in the similarity department, so... is Rust really any different then? There is a part of these examples that we skipped over - actually doing something with the values.</p> +<h2 id="moving-around-is-fun">Moving around is fun</h2> +<p>Let's expand on the last example. The scoping is not really important for that one, so we don't include it here.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// same thing, &#39;s&#39; is now an owner +</span><span> +</span><span style="color:#8959a8;">let</span><span> s2 </span><span style="color:#3e999f;">=</span><span> s; </span><span style="color:#999999;">// easy, &#39;s2&#39; becomes another owner... right? +</span><span> +</span><span>println!(</span><span style="color:#718c00;">&quot;And the contents are: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s); </span><span style="color:#999999;">// this doesn&#39;t work, can you guess why? +</span></code></pre> +<p>At first glance everything looks great. If we write this code (well, an equivalent of it) in basically any other popular language, it will compile no issue - but it does not here and there's a good reason why.</p> +<p>To understand what's happening, we have to consult the rules again, rule 2 in particular. It says that there can only be one owner of any value at a given time. So, <code>s</code> and <code>s2</code> cannot own the same object. Okay, makes sense, but what is happening in this line then - <code>let s2 = s;</code>? Experience probably tells you that <code>s</code> just gets copied into <code>s2</code>, creating a new String object. That would result in each variable owning its very own instance of the string and each instance having exactly one owner. Sounds like everyone should be happy now, but wait - in that case the last line should work no issue, right? But it doesn't, so can't be a copy. Let's see now what the compiler actually has to say:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0382]: borrow of moved value: `s` +</span><span> --&gt; src/main.rs:6:42 +</span><span> | +</span><span>2 | let s = String::from(&quot;a string&quot;); +</span><span> | - move occurs because `s` has type `String`, which does not implement the `Copy` trait +</span><span>3 | +</span><span>4 | let s2 = s; +</span><span> | - value moved here +</span><span>5 | +</span><span>6 | println!(&quot;And the contents are: {}&quot;, s); +</span><span> | ^ value borrowed here after move +</span></code></pre> +<p><em>&quot;value moved here&quot;</em> - gotcha! So <code>s</code> is being moved to <code>s2</code>, which also means that <code>s2</code> now becomes the new owner of the string being moved and <code>s</code> cannot be used anymore. In Rust, the default method of passing values around is by move, not by copy. While it may sound a bit odd at first, it actually has some very interesting implications. But before we get to them, let's fix our code, so it compiles now. To do so, we have to explicitly tell Rust to make a copy by invoking the <code>clone</code> method:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// &#39;s&#39; is an owner +</span><span> +</span><span style="color:#8959a8;">let</span><span> s2 </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">clone</span><span>(); </span><span style="color:#999999;">// &#39;s2&#39; now contains its own copy +</span><span> +</span><span>println!(</span><span style="color:#718c00;">&quot;And the contents are: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s); </span><span style="color:#999999;">// success! +</span></code></pre> +<p>The compiler is happy now and so are we. The implicit move takes some getting used to, but the compiler is here to help us. Now, let's put the good, old C++ on the table again and compare the two lines:</p> +<div style="text-align: center"> +<p><code>let s2 = s;</code> is equivalent to <code>auto s2 = std::move(s);</code></p> +<p><code>let s2 = s.clone()</code> is equivalent to <code>auto s2 = s</code></p> +</div> +<p>There are a few important things to note here:</p> +<ul> +<li> +<p>Making a copy is oftentimes not cheap. Memory needs to be allocated and copied, and a call to the system has to be made. We should prefer to move things as much as possible to avoid this cost - in C++ we have a myriad of language features like <code>std::move</code> and <em>r-references</em> to achieve this. Every programmer worth their salt needs to be well versed in all of them to write efficient C++ code and simply forgetting one move can lead to significant performance loss (and this happens to even the most senior devs ever existing, let's not pretend). On the contrary, in Rust you need to make an effort to make a copy and that makes you very aware of the cost you're paying - something that we'll see quite a lot of in the language. Also, if you forget a clone there's no harm done - it just won't compile!</p> +</li> +<li> +<p>Hidden in all of this is another nice thing Rust gives us. In C++, nothing prevents you from using variables after they've been moved from, leading to unexpected errors in a more complex code. In Rust, that variable (in our case <code>s</code>) simply becomes invalid and the compiler gives us a nice error about it.</p> +</li> +</ul> +<h3 id="but-what-about-ints">But what about ints?</h3> +<p>A good question to ask. Copying primitives is cheap. And it's not convenient for the programmer to have to always write <code>.clone()</code> after every primitive. If we take a look at the error from the previous example:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>move occurs because `s` has type `String`, which does not implement the `Copy` trait` +</span></code></pre> +<p>It says that <code>s</code> was moved because the <code>String</code> type doesn't have the <code>Copy</code> trait. We will talk about traits more in depth in the future lessons, but what this basically means is that <code>String</code> is not specified to be copied by default. All primitive types (<code>i32</code>, <code>bool</code>, <code>f64</code>, <code>char</code>, etc.) and tuples consisting only of primitive types implement the <code>Copy</code> trait.</p> +<h3 id="exercise">Exercise</h3> +<p>How to fix that code?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, s); +</span><span>} +</span></code></pre> +<h2 id="let-s-borrow-some-books">Let's borrow some books</h2> +<p>We now know how to move things around and how to clone them if moving is not possible. But what if making a copy is unnecessary - maybe we just want to let someone look at our resource and keep on holding onto it once they're done. Consider the following example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(book.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Book is still there: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>Cloning is pretty excessive here. Imagine recommending a book to your friend and instead of lending it to them for the weekend, you scan it and print an exact copy. Not the best way to go about it, is it? Thankfully, Rust allows us to access a resource without becoming an owner through the use of references and the <code>&amp;</code> operator. This is called a borrow.</p> +<p>The adjusted code should look like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>book); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Book is still there: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>As with everything, references are too, by default, immutable, which means that the <code>read_book</code> function is not able to modify that book passed into it. We can also borrow something mutably by specifying it both in the receiving function signature and the place it gets called. Maybe you want to have your book signed by its author?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">sign_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> String) { +</span><span> book.</span><span style="color:#4271ae;">push_str</span><span>(</span><span style="color:#718c00;">&quot; ~ Arthur Author&quot;</span><span>); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// note that the book has to be marked as mutable in the first place +</span><span> </span><span style="color:#8959a8;">let mut</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">sign_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> book); </span><span style="color:#999999;">// it&#39;s always clear when a parameter might get modified +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); </span><span style="color:#999999;">// book is now signed +</span><span>} +</span></code></pre> +<p>Pretty neat, but doesn't seem that safe right now. Let's try to surprise our friend:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">erase_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> String) { +</span><span> book.</span><span style="color:#4271ae;">clear</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>book; </span><span style="color:#999999;">// an immutable borrow +</span><span> +</span><span> </span><span style="color:#4271ae;">erase_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> book); </span><span style="color:#999999;">// a mutable borrow +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(r); </span><span style="color:#999999;">// would be pretty sad to open a blank book when it was not +</span><span> </span><span style="color:#999999;">// what we borrowed initially +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>Fortunately for us (and our poor friend just wanting to read), the compiler steps in and doesn't let us do that, printing the following message:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0502]: cannot borrow `book` as mutable because it is also borrowed as immutable +</span><span> --&gt; src/main.rs:14:14 +</span><span> | +</span><span>12 | let r = &amp;book; // an immutable borrow +</span><span> | ----- immutable borrow occurs here +</span><span>13 | +</span><span>14 | erase_book(&amp;mut book); // a mutable borrow +</span><span> | ^^^^^^^^^ mutable borrow occurs here +</span><span>15 | +</span><span>16 | read_book(r); // would be pretty sad to open a blank book when it was not +</span><span> | - immutable borrow later used here +</span></code></pre> +<p>This is where the famous borrow checker comes in. To keep things super safe, Rust clearly states what can and cannot be done with references and tracks their lifetimes. Exactly one of the following is always true for references to a given resource:</p> +<ul> +<li> +<p>There exists only one mutable reference and no immutable references, <strong>or</strong></p> +</li> +<li> +<p>There is any number of immutable references and no mutable ones.</p> +</li> +</ul> +<p>You may notice a parallel to the <em>readers - writers</em> problem from concurrent programming. In fact, the way Rust's borrow checker is designed lends itself incredibly well to preventing data race related issues.</p> +<h3 id="dangling-references">Dangling references</h3> +<p>Rust also checks for dangling references. If we try to compile the following code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> reference_to_nothing </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">dangle</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dangle</span><span>() -&gt; </span><span style="color:#3e999f;">&amp;</span><span>String { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;hello&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>s +</span><span>} +</span></code></pre> +<p>we will get an adequate error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0106]: missing lifetime specifier +</span><span> --&gt; src/main.rs:5:16 +</span><span> | +</span><span>5 | fn dangle() -&gt; &amp;String { +</span><span> | ^ expected named lifetime parameter +</span><span> | +</span><span> = help: this function&#39;s return type contains a borrowed value, but there is no value for it to be borrowed from +</span><span>help: consider using the `&#39;static` lifetime +</span><span> | +</span><span>5 | fn dangle() -&gt; &amp;&#39;static String { +</span><span> | ^^^^^^^^ +</span></code></pre> +<p>The message above suggests specifing a lifetime for the returned string. In Rust, the lifetime of each variable is also a part of its type, but we will talk more about it later.</p> +<h3 id="exercise-1">Exercise</h3> +<p>Our previous solution using <code>clone()</code> was pretty inefficient. How should this code look now?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, s.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, s.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, s); </span><span style="color:#999999;">// we could&#39;ve ommitted the clone() here. Why? +</span><span>} +</span></code></pre> +<h2 id="everyone-gets-a-slice">Everyone gets a slice</h2> +<p>The last part of working with references that we will cover in this lesson are slices. A <em>slice</em> in Rust is a view over continuous data. Let us start with a string slice - the <code>&amp;str</code> type.</p> +<p><em><strong>Note:</strong> for the purposes of these examples we assume we are working with ASCII strings. More comprehensive articles on handling strings are linked at the end of this lesson.</em></p> +<p>To create a string slice from the <code>String</code> object <code>s</code>, we can simply write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#f5871f;">1</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">3</span><span>]; </span><span style="color:#999999;">// creates a slice of length 2, starting with the character at index 1 +</span></code></pre> +<p>This makes use of the <code>&amp;</code> operator and Rust's range notation to specify the beginning and end of the slice. Thus, we can also write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#f5871f;">2</span><span style="color:#3e999f;">..</span><span>]; </span><span style="color:#999999;">// everything from index 2 till the end +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">1</span><span>]; </span><span style="color:#999999;">// only the first byte +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#3e999f;">..</span><span>]; </span><span style="color:#999999;">// the whole string as a slice +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">as_str</span><span>(); </span><span style="color:#999999;">// also the whole string +</span></code></pre> +<p>You might have noticed that we always built <code>String</code> values using the <code>from()</code> method and never actually used the string literals directly. What type is a string literal then? Turns out it's the new string slice we just learned about!</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;string literal&quot;</span><span>; +</span></code></pre> +<p>In fact, it makes a lot sense - string literals, after all, are not allocated on the heap, but rather placed in a special section of the resulting binary. It's only natural we just reference that place with a slice.</p> +<p>Slices can also be taken from arrays:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> array: [</span><span style="color:#8959a8;">i32</span><span>; </span><span style="color:#f5871f;">4</span><span>] </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">42</span><span>, </span><span style="color:#f5871f;">10</span><span>, </span><span style="color:#f5871f;">5</span><span>, </span><span style="color:#f5871f;">2</span><span>]; </span><span style="color:#999999;">// creates an array of four 32 bit integers +</span><span style="color:#8959a8;">let</span><span> slice: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">i32</span><span>] </span><span style="color:#3e999f;">= &amp;</span><span>array[</span><span style="color:#f5871f;">1</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">3</span><span>]; </span><span style="color:#999999;">// results in a slice [10, 5] +</span></code></pre> +<h3 id="exercise-2">Exercise</h3> +<p>Can this code still be improved from the previous version utilizing references? Think about the signature of <code>count_animals</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span>} +</span></code></pre> +<h3 id="further-reading">Further reading</h3> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/std/primitive.char.html">Char documentation</a></p> +</li> +<li> +<p><a href="https://fasterthanli.me/articles/working-with-strings-in-rust">Working with strings in Rust</a></p> +</li> +<li> +<p><a href="https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html">The Book, chapter 4</a></p> +</li> +</ul> +<h3 id="assignment-1-graded">Assignment 1 (graded)</h3> +<p><a href="https://classroom.github.com/a/prGDl5Xa">ordering in Van Binh</a></p> +<p>Deadline: 16.10.2024 23:59</p> + + + + + Organizational lesson + 2024-10-06T00:00:00+00:00 + 2024-10-06T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/00-organizational/ + + <h1 id="rust-course">Rust course</h1> +<p>We will be using <a href="https://classroom.github.com">Github Classroom</a> for task submission and <a href="https://discord.gg/UyvepYkPs9">Discord</a> for discussions.</p> +<p>Our main learning/teaching resource will be <a href="https://doc.rust-lang.org/stable/book/">&quot;The Book&quot;</a>.</p> +<p>Also worth mentioning: <a href="https://doc.rust-lang.org/rust-by-example/index.html">&quot;Rust by Example&quot;</a>.</p> +<h2 id="grading">Grading</h2> +<ul> +<li>1/3 of the grade is based on small tasks. There will be approximately 1 task every two weeks and each task will be graded on a scale of 0 to 3.</li> +<li>2/3 of the grade is based on a big project. You can choose a topic yourself, but it must be accepted by me. The project has to be split into two parts. It can be done in groups of two (or bigger, if ambitious enough).</li> +<li>The grade may be increased by a bonus. You can get a bonus for: +<ul> +<li>Making a presentation about some advanced topic (const generics, futures, macros, etc.) or about architecture of a selected Rust open-source library</li> +<li>Contributing to a selected Rust open-source library</li> +<li>Contributing to this course's materials</li> +<li>Quizzes, homeworks, general activity etc.</li> +</ul> +</li> +</ul> +<h2 id="project-deadlines">Project Deadlines</h2> +<ol> +<li>2024-11-7: Project ideas should be presented to me for further refining. If you wish to pair up with someone, now is the time to tell me.</li> +<li>2024-11-14: Final project ideas should be accepted by now.</li> +<li>2024-12-12: Deadline for submitting the first part of the project.</li> +<li>2025-01-09: Deadline for submitting the second and final part of the project.</li> +</ol> + + + + + Introduction to Rust + 2024-09-20T00:00:00+00:00 + 2024-09-20T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/01-introduction/ + + <p><img src="https://www.rust-lang.org/logos/rust-logo-blk.svg" alt="Logo" /></p> +<h1 id="a-language-empowering-everyone-to-build-reliable-and-efficient-software">A language empowering everyone to build reliable and efficient software.</h1> +<p>(<a href="https://rustacean.net/">unofficial logo</a>)</p> +<h2 id="why-use-rust">Why use Rust?</h2> +<ul> +<li>It is <strong>safe</strong> (compared to C++ for example, as we will see in a minute)</li> +<li>It is <strong>fast</strong> (because it is compiled to machine code)</li> +<li>It is ergonomic and pleasant to use (static typing, expressive type system, helpful compiler +warnings)</li> +<li>It +is <a href="https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-programming-scripting-and-markup-languages">loved by programmers</a></li> +<li>It provides excellent tooling</li> +</ul> +<h2 id="why-learn-rust">Why learn Rust?</h2> +<p>Even if you don't end up using Rust, learning it expands your horizons</p> +<ul> +<li>it helps especially with the awareness of what you can and can't do in concurrent applications</li> +<li>it helps you understand memory management and learn its good practices</li> +</ul> +<h2 id="why-not-to-learn-rust">Why not to learn Rust?</h2> +<ul> +<li>Some people say Rust is too hard to learn because of the borrow checker</li> +<li>Once you get to know Cargo you won't ever want to use a language without a built-in package +manager ;)</li> +<li>You will start hating C++</li> +</ul> +<h2 id="demos">Demos</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/cpp_meme.jpg" alt="Meme" /></p> +<p>Let's compare the same code written in <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/errors_demo.c">C</a>, <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/errors_demo.cpp">C++</a> +and <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/errors_demo.rs">Rust</a>.</p> +<h2 id="code-you-sent-in-previous-editions">Code you sent in previous editions!</h2> +<h3 id="aleksander-tudruj">Aleksander Tudruj</h3> +<pre data-lang="cpp" style="background-color:#ffffff;color:#4d4d4c;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;iostream&gt; +</span><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;unordered_map&gt; +</span><span> +</span><span style="color:#8959a8;">using </span><span>name </span><span style="color:#3e999f;">=</span><span> std::string; +</span><span style="color:#8959a8;">using </span><span>age </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">int</span><span>; +</span><span style="color:#8959a8;">using </span><span>person </span><span style="color:#3e999f;">=</span><span> std::pair&lt;name, age&gt;; +</span><span style="color:#8959a8;">using </span><span>address </span><span style="color:#3e999f;">=</span><span> std::string; +</span><span style="color:#8959a8;">using </span><span>address_book </span><span style="color:#3e999f;">=</span><span> std::unordered_map&lt;person, address&gt;; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_address_book</span><span>(</span><span style="color:#8959a8;">const</span><span> address_book </span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">book</span><span>) +</span><span>{ +</span><span> </span><span style="color:#8959a8;">for </span><span>(</span><span style="color:#8959a8;">const auto </span><span style="color:#3e999f;">&amp;</span><span>[person, address] </span><span style="color:#3e999f;">:</span><span> book) +</span><span> { +</span><span> std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> person.</span><span style="color:#c82829;">first </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&quot; is &quot; </span><span style="color:#3e999f;">&lt;&lt;</span><span> person.</span><span style="color:#c82829;">second </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&quot; years old and lives at &quot; </span><span style="color:#3e999f;">&lt;&lt;</span><span> address </span><span style="color:#3e999f;">&lt;&lt;</span><span> std::endl; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() +</span><span>{ +</span><span> +</span><span> address_book </span><span style="color:#c82829;">people</span><span style="color:#4271ae;">{}</span><span>; +</span><span> people.</span><span style="color:#c82829;">insert</span><span>({{</span><span style="color:#718c00;">&quot;John&quot;</span><span>, </span><span style="color:#f5871f;">20</span><span>}, </span><span style="color:#718c00;">&quot;221B Baker Street, London&quot;</span><span>}); +</span><span> people.</span><span style="color:#c82829;">insert</span><span>({{</span><span style="color:#718c00;">&quot;Mary&quot;</span><span>, </span><span style="color:#f5871f;">30</span><span>}, </span><span style="color:#718c00;">&quot;Avenue des Champs-Élysées, Paris&quot;</span><span>}); +</span><span> people.</span><span style="color:#c82829;">insert</span><span>({{</span><span style="color:#718c00;">&quot;Jack&quot;</span><span>, </span><span style="color:#f5871f;">73</span><span>}, </span><span style="color:#718c00;">&quot;Wall Street, New York&quot;</span><span>}); +</span><span> </span><span style="color:#c82829;">print_address_book</span><span style="color:#4271ae;">(people)</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">return </span><span style="color:#f5871f;">0</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/tudruj.cpp">tudruj.cpp</a>)</sub></p> +<h3 id="krystyna-gasinska">Krystyna Gasińska</h3> +<pre data-lang="python" style="background-color:#ffffff;color:#4d4d4c;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#999999;"># sample 1 - different ways of removing elements from the list while iterating +</span><span>list1 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list1)</span><span>: +</span><span> </span><span style="color:#8959a8;">del </span><span>item +</span><span>list1 +</span><span> +</span><span style="color:#999999;"># [1, 2, 3, 4] +</span><span> +</span><span>list2 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list2)</span><span>: +</span><span> </span><span style="color:#4271ae;">list2.</span><span style="color:#c82829;">remove</span><span style="color:#4271ae;">(item) +</span><span>list2 +</span><span> +</span><span style="color:#999999;"># [2, 4] +</span><span> +</span><span>list3 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list3[:])</span><span>: +</span><span> </span><span style="color:#4271ae;">list3.</span><span style="color:#c82829;">remove</span><span style="color:#4271ae;">(item) +</span><span>list3 +</span><span> +</span><span style="color:#999999;"># [] +</span><span> +</span><span>list4 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list4)</span><span>: +</span><span> </span><span style="color:#4271ae;">list4.</span><span style="color:#c82829;">pop</span><span style="color:#4271ae;">(idx) +</span><span>list4 +</span><span> +</span><span style="color:#999999;"># [2, 4] +</span><span> +</span><span style="color:#999999;"># sample 2 - string interning +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc&quot; +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc&quot; +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&#39;&#39;</span><span style="color:#4271ae;">.</span><span style="color:#c82829;">join</span><span style="color:#4271ae;">([</span><span style="color:#718c00;">&#39;a&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;b&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;c&#39;</span><span style="color:#4271ae;">]) +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&#39;&#39;</span><span style="color:#4271ae;">.</span><span style="color:#c82829;">join</span><span style="color:#4271ae;">([</span><span style="color:#718c00;">&#39;a&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;b&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;c&#39;</span><span style="color:#4271ae;">]) +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc!&quot; +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc!&quot; +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span style="color:#999999;"># sample 3 - chained operations +</span><span>(</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">False</span><span>) </span><span style="color:#3e999f;">in </span><span>[</span><span style="color:#f5871f;">False</span><span>] +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">== </span><span>(</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">in </span><span>[</span><span style="color:#f5871f;">False</span><span>]) +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">in </span><span>[</span><span style="color:#f5871f;">False</span><span>] </span><span style="color:#999999;"># unexpected... +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span style="color:#999999;"># sample 4 - is operator +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">256 +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">256 +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">257 +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">257 +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span>a, b </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">257</span><span>, </span><span style="color:#f5871f;">257 +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span style="color:#f5871f;">257 </span><span style="color:#3e999f;">is </span><span style="color:#f5871f;">257 +</span><span> +</span><span style="color:#999999;"># &lt;&gt;:1: SyntaxWarning: &quot;is&quot; with a literal. Did you mean &quot;==&quot;? +</span><span style="color:#999999;"># &lt;&gt;:1: SyntaxWarning: &quot;is&quot; with a literal. Did you mean &quot;==&quot;? +</span><span style="color:#999999;"># C:\Users\kgasinsk\AppData\Local\Temp\ipykernel_15776\331119389.py:1: SyntaxWarning: &quot;is&quot; with a literal. Did you mean &quot;==&quot;? +</span><span style="color:#999999;"># 257 is 257 +</span><span> +</span><span style="color:#999999;"># sample 5 - local variables +</span><span style="color:#8959a8;">def </span><span style="color:#4271ae;">f</span><span>(</span><span style="color:#f5871f;">trufel</span><span>): +</span><span> </span><span style="color:#8959a8;">if </span><span>trufel: +</span><span> y </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">1 +</span><span> y </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1 +</span><span> +</span><span style="color:#c82829;">f</span><span style="color:#4271ae;">(</span><span style="color:#f5871f;">True</span><span style="color:#4271ae;">) </span><span style="color:#999999;"># everything is fine +</span><span> +</span><span style="color:#c82829;">f</span><span style="color:#4271ae;">(</span><span style="color:#f5871f;">False</span><span style="color:#4271ae;">) </span><span style="color:#999999;"># gives error: local variable &#39;y&#39; referenced before assignment +</span><span> +</span><span style="color:#999999;"># --------------------------------------------------------------------------- +</span><span style="color:#999999;"># UnboundLocalError Traceback (most recent call last) +</span><span style="color:#999999;"># Input In [17], in &lt;cell line: 1&gt;() +</span><span style="color:#999999;"># ----&gt; 1 f(False) +</span><span> +</span><span style="color:#999999;"># Input In [15], in f(trufel) +</span><span style="color:#999999;"># 3 if trufel: +</span><span style="color:#999999;"># 4 y = 1 +</span><span style="color:#999999;"># ----&gt; 5 y += 1 +</span><span> +</span><span style="color:#999999;"># UnboundLocalError: local variable &#39;y&#39; referenced before assignment +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/gasinska.py">gasinska.py</a>)</sub></p> +<h3 id="antoni-koszowski">Antoni Koszowski</h3> +<pre data-lang="go" style="background-color:#ffffff;color:#4d4d4c;" class="language-go "><code class="language-go" data-lang="go"><span style="color:#999999;">// mutowalność jest wbudowana w język +</span><span> +</span><span style="color:#8959a8;">type </span><span>S </span><span style="color:#8959a8;">struct </span><span>{ +</span><span> </span><span style="color:#c82829;">A </span><span style="color:#c99e00;">string +</span><span> </span><span style="color:#c82829;">B </span><span>[]</span><span style="color:#c99e00;">string +</span><span>} +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#c82829;">x </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">S</span><span>{</span><span style="color:#718c00;">&quot;x-A&quot;</span><span>, []</span><span style="color:#c99e00;">string</span><span>{</span><span style="color:#718c00;">&quot;x-B&quot;</span><span>}} +</span><span> </span><span style="color:#c82829;">y </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">x </span><span style="color:#999999;">// copy the struct +</span><span> </span><span style="color:#c82829;">y</span><span>.</span><span style="color:#c82829;">A </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;y-A&quot; +</span><span> </span><span style="color:#c82829;">y</span><span>.</span><span style="color:#c82829;">B</span><span>[</span><span style="color:#f5871f;">0</span><span>] </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;y-B&quot; +</span><span> +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Println</span><span>(</span><span style="color:#c82829;">x</span><span>, </span><span style="color:#c82829;">y</span><span>) +</span><span> </span><span style="color:#999999;">// Outputs &quot;{x-A [y-B]} {y-A [y-B]}&quot; -- x was modified! +</span><span>} +</span><span> +</span><span style="color:#999999;">// slices i kwestia append +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">doStuff</span><span>(</span><span style="color:#f5871f;">value </span><span>[]</span><span style="color:#c99e00;">string</span><span>) { +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Printf</span><span>(</span><span style="color:#718c00;">&quot;value=</span><span style="color:#666969;">%v</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">value</span><span>) +</span><span> +</span><span> </span><span style="color:#c82829;">value2 </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">value</span><span>[:] +</span><span> </span><span style="color:#c82829;">value2 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">append</span><span>(</span><span style="color:#c82829;">value2</span><span>, </span><span style="color:#718c00;">&quot;b&quot;</span><span>) +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Printf</span><span>(</span><span style="color:#718c00;">&quot;value=</span><span style="color:#666969;">%v</span><span style="color:#718c00;">, value2=</span><span style="color:#666969;">%v</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">value</span><span>, </span><span style="color:#c82829;">value2</span><span>) +</span><span> +</span><span> </span><span style="color:#c82829;">value2</span><span>[</span><span style="color:#f5871f;">0</span><span>] </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;z&quot; +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Printf</span><span>(</span><span style="color:#718c00;">&quot;value=</span><span style="color:#666969;">%v</span><span style="color:#718c00;">, value2=</span><span style="color:#666969;">%v</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">value</span><span>, </span><span style="color:#c82829;">value2</span><span>) +</span><span>} +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#c82829;">slice1 </span><span style="color:#3e999f;">:= </span><span>[]</span><span style="color:#c99e00;">string</span><span>{</span><span style="color:#718c00;">&quot;a&quot;</span><span>} </span><span style="color:#999999;">// length 1, capacity 1 +</span><span> +</span><span> </span><span style="color:#c82829;">doStuff</span><span>(</span><span style="color:#c82829;">slice1</span><span>) +</span><span> </span><span style="color:#999999;">// Output: +</span><span> </span><span style="color:#999999;">// value=[a] -- ok +</span><span> </span><span style="color:#999999;">// value=[a], value2=[a b] -- ok: value unchanged, value2 updated +</span><span> </span><span style="color:#999999;">// value=[a], value2=[z b] -- ok: value unchanged, value2 updated +</span><span> +</span><span> </span><span style="color:#c82829;">slice10 </span><span style="color:#3e999f;">:= </span><span style="color:#4271ae;">make</span><span>([]</span><span style="color:#c99e00;">string</span><span>, </span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">10</span><span>) </span><span style="color:#999999;">// length 1, capacity 10 +</span><span> </span><span style="color:#c82829;">slice10</span><span>[</span><span style="color:#f5871f;">0</span><span>] </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;a&quot; +</span><span> +</span><span> </span><span style="color:#c82829;">doStuff</span><span>(</span><span style="color:#c82829;">slice10</span><span>) +</span><span> </span><span style="color:#999999;">// Output: +</span><span> </span><span style="color:#999999;">// value=[a] -- ok +</span><span> </span><span style="color:#999999;">// value=[a], value2=[a b] -- ok: value unchanged, value2 updated +</span><span> </span><span style="color:#999999;">// value=[z], value2=[z b] -- WTF?!? value changed??? +</span><span>} +</span><span> +</span><span style="color:#999999;">// error handling +</span><span> +</span><span style="color:#c82829;">len</span><span>, </span><span style="color:#c82829;">err </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">reader</span><span>.</span><span style="color:#c82829;">Read</span><span>(</span><span style="color:#c82829;">bytes</span><span>) +</span><span style="color:#8959a8;">if </span><span style="color:#c82829;">err </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">nil </span><span>{ +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">err </span><span style="color:#3e999f;">== </span><span style="color:#c82829;">io</span><span>.</span><span style="color:#c82829;">EOF </span><span>{ +</span><span> </span><span style="color:#999999;">// All good, end of file +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#8959a8;">return </span><span style="color:#c82829;">err +</span><span> } +</span><span>} +</span><span> +</span><span> +</span><span style="color:#999999;">// interfejs nil +</span><span> +</span><span style="color:#8959a8;">type </span><span>Explodes </span><span style="color:#8959a8;">interface </span><span>{ +</span><span> </span><span style="color:#4271ae;">Bang</span><span>() +</span><span> </span><span style="color:#4271ae;">Boom</span><span>() +</span><span>} +</span><span> +</span><span style="color:#999999;">// Type Bomb implements Explodes +</span><span style="color:#8959a8;">type </span><span>Bomb </span><span style="color:#8959a8;">struct </span><span>{} +</span><span style="color:#8959a8;">func </span><span>(</span><span style="color:#3e999f;">*</span><span style="color:#8959a8;">Bomb</span><span>) </span><span style="color:#4271ae;">Bang</span><span>() {} +</span><span style="color:#8959a8;">func </span><span>(</span><span style="color:#8959a8;">Bomb</span><span>) </span><span style="color:#4271ae;">Boom</span><span>() {} +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">var </span><span style="color:#c82829;">bomb </span><span style="color:#3e999f;">*</span><span style="color:#8959a8;">Bomb </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">nil +</span><span> </span><span style="color:#8959a8;">var </span><span style="color:#c82829;">explodes </span><span style="color:#8959a8;">Explodes </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">bomb +</span><span> </span><span style="color:#4271ae;">println</span><span>(</span><span style="color:#c82829;">bomb</span><span>, </span><span style="color:#c82829;">explodes</span><span>) </span><span style="color:#999999;">// &#39;0x0 (0x10a7060,0x0)&#39; +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">explodes </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">nil </span><span>{ +</span><span> </span><span style="color:#4271ae;">println</span><span>(</span><span style="color:#718c00;">&quot;Not nil!&quot;</span><span>) </span><span style="color:#999999;">// &#39;Not nil!&#39; What are we doing here?!?! +</span><span> </span><span style="color:#c82829;">explodes</span><span>.</span><span style="color:#c82829;">Bang</span><span>() </span><span style="color:#999999;">// works fine +</span><span> </span><span style="color:#c82829;">explodes</span><span>.</span><span style="color:#c82829;">Boom</span><span>() </span><span style="color:#999999;">// panic: value method main.Bomb.Boom called using nil *Bomb pointer +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#4271ae;">println</span><span>(</span><span style="color:#718c00;">&quot;nil!&quot;</span><span>) </span><span style="color:#999999;">// why don&#39;t we end up here? +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// ubogie struktury danych, takie customowe tracą type safety m.in poprzez castowanie do interface{} +</span><span style="color:#999999;">// kiedyś brak generyków, choć teraz w znacznym stopniu problem został rozwiązany. +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/koszowski.go">koszowski.go</a>)</sub></p> +<h3 id="mieszko-grodzicki">Mieszko Grodzicki</h3> +<pre data-lang="python" style="background-color:#ffffff;color:#4d4d4c;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#8959a8;">def </span><span style="color:#4271ae;">add_contents</span><span>(</span><span style="color:#f5871f;">input_list</span><span>, </span><span style="color:#f5871f;">contents</span><span style="color:#3e999f;">=</span><span>[]): +</span><span> </span><span style="color:#8959a8;">for </span><span>val </span><span style="color:#8959a8;">in </span><span>input_list: +</span><span> </span><span style="color:#4271ae;">contents.</span><span style="color:#c82829;">append</span><span style="color:#4271ae;">(val) +</span><span> </span><span style="color:#8959a8;">return </span><span>contents +</span><span> +</span><span style="color:#4271ae;">print(</span><span style="color:#c82829;">add_contents</span><span style="color:#4271ae;">([</span><span style="color:#f5871f;">1</span><span style="color:#4271ae;">])) </span><span style="color:#999999;"># [1] +</span><span style="color:#4271ae;">print(</span><span style="color:#c82829;">add_contents</span><span style="color:#4271ae;">([</span><span style="color:#f5871f;">2</span><span style="color:#4271ae;">])) </span><span style="color:#999999;"># [1, 2] +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/grodzicki.py">grodzicki.py</a>)</sub></p> +<h2 id="installing-rust">Installing Rust</h2> +<ul> +<li><a href="https://rustup.rs/">Rustup</a></li> +<li>Setup an IDE +<ul> +<li><a href="https://www.jetbrains.com/clion/">CLion</a> (you can get +it <a href="https://www.jetbrains.com/community/education/">for free</a>) +and <a href="https://intellij-rust.github.io/">RustRover</a></li> +<li><a href="https://code.visualstudio.com/">VSCode</a> +and <a href="https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer">rust-analyzer</a></li> +<li>rust-analyzer also works +with <a href="https://rust-analyzer.github.io/manual.html#installation">other IDEs</a></li> +</ul> +</li> +</ul> +<h2 id="useful-tools">Useful tools</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/clippy.jpg" alt="Clippy" /></p> +<ul> +<li><code>cargo clippy</code> (for static analysis)</li> +<li>there's also <code>cargo check</code>, but it's less powerful than clippy</li> +<li><code>cargo fmt</code> (for code formatting)</li> +</ul> +<h3 id="rust-playground">Rust Playground</h3> +<ul> +<li><a href="https://play.rust-lang.org/">online Rust compiler</a></li> +</ul> +<h2 id="hello-world">Hello world</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;World&quot;</span><span>; +</span><span> println!(</span><span style="color:#718c00;">&quot;Hello, </span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, name); </span><span style="color:#999999;">// using the println! macro +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/hello_world.rs">hello_world.rs</a>)</sub></p> +<h3 id="variables">Variables</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40</span><span>; </span><span style="color:#999999;">// inferred type +</span><span> </span><span style="color:#8959a8;">let</span><span> y: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">100</span><span>; </span><span style="color:#999999;">// specified type +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40 </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">2</span><span>; </span><span style="color:#999999;">// shadowing +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x); </span><span style="color:#999999;">// prints 42 +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// x = 0; // compilation error, variables are by default immutable +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40</span><span>; </span><span style="color:#999999;">// declare as mutable +</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#999999;">// now we can reassign +</span><span> +</span><span> x </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; </span><span style="color:#999999;">// x = x + 1 +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/variables.rs">variables.rs</a>)</sub></p> +<h3 id="conditionals">Conditionals</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">42 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is 42&quot;</span><span>); +</span><span> } </span><span style="color:#8959a8;">else if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">43 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is 43&quot;</span><span>); +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is not 42 or 43&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// we can also use ifs as expressions +</span><span> </span><span style="color:#8959a8;">let</span><span> a_or_b </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;a&quot; </span><span style="color:#999999;">// notice no semicolon at the end +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;b&quot; +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/conditionals.rs">conditionals.rs</a>)</sub></p> +<h3 id="loops">Loops</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;i is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, i); </span><span style="color:#999999;">// i in [0, 10) +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">while</span><span> x </span><span style="color:#3e999f;">&lt; </span><span style="color:#f5871f;">50 </span><span>{ +</span><span> x </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> y </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let mut</span><span> iterations </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> iterations </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> iterations </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#8959a8;">continue</span><span>; +</span><span> } +</span><span> y </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> y </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// we can use labels to refer to a specific loop +</span><span> </span><span style="color:#8959a8;">let mut</span><span> count </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> &#39;counting_up: </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> remaining </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">10</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> remaining </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">9 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> </span><span style="color:#8959a8;">if</span><span> count </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">2 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break &#39;counting_up</span><span>; </span><span style="color:#999999;">// ends the outer loop +</span><span> } +</span><span> remaining </span><span style="color:#3e999f;">-= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> count </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use break with a value. +</span><span> </span><span style="color:#999999;">// Because loops are expressions too, +</span><span> </span><span style="color:#999999;">// the value we break with will be returned from the functions +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> value </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> counter </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break </span><span style="color:#f5871f;">32</span><span>; +</span><span> } +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/loops.rs">loops.rs</a>)</sub></p> +<h3 id="functions">Functions</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">get_5</span><span>() -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#f5871f;">5 </span><span style="color:#999999;">// we could also write &quot;return 5;&quot; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">print_sum</span><span>(</span><span style="color:#f5871f;">a</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">b</span><span>: </span><span style="color:#8959a8;">u32</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;a + b = </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, a </span><span style="color:#3e999f;">+</span><span> b); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">100</span><span>; +</span><span> </span><span style="color:#4271ae;">print_sum</span><span>(a, </span><span style="color:#4271ae;">get_5</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/01-introduction/functions.rs">functions.rs</a>)</sub></p> +<h2 id="test-assignment-not-graded">Test assignment (not graded)</h2> +<p>Click <a href="https://classroom.github.com/a/l3iF_TJU">here</a></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/book/">The Book, chapters 1-3</a></li> +</ul> +<h2 id="additional-reading">Additional reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/rust-by-example/">Rust By Example</a></li> +</ul> + + + + + Project feedback + 2022-12-29T00:00:00+00:00 + 2022-12-29T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/12-project-feedback/ + + <h1 id="project-feedback">Project feedback</h1> +<h2 id="unwrapping-options-results">Unwrapping options/results</h2> +<p>Always ask yourself twice if you really need to unwrap. In most cases, you don't have to. Use pattern matching instead, +as it provides a static guarantee that the value is present.</p> +<p>Pattern matching prevents you from writing code like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">some_function</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">is_some</span><span>() { +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x.</span><span style="color:#4271ae;">unwrap</span><span>()); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Let&#39;s say this line was added later and/or you forgot to put it in the if statement. +</span><span> </span><span style="color:#4271ae;">do_something</span><span>(x.</span><span style="color:#4271ae;">unwrap</span><span>()); </span><span style="color:#999999;">// this will blow up if x == None! +</span><span>} +</span></code></pre> +<p>Instead, you can write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">some_function</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(x) </span><span style="color:#3e999f;">=</span><span> x { +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x); +</span><span> </span><span style="color:#4271ae;">do_something</span><span>(x); +</span><span> } +</span><span>} +</span></code></pre> +<h2 id="question-mark-operator">Question mark operator</h2> +<p>In methods that return <code>Result</code> or <code>Option</code>, you can use the question mark operator to return early if the value is <code>None</code> or <code>Err</code>. +See: <a href="https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html">https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html</a></p> +<h2 id="logging">Logging</h2> +<p>You can use the <a href="https://crates.io/crates/log">log</a> crate to log messages. It's better than <code>println!</code> because it +can be easily turned off. It also allows you to use different severity levels (e.g. <code>info</code>, <code>warn</code>, <code>error</code>) and only +log messages above a certain level.</p> +<h2 id="string-vs-str">&amp;String vs &amp;str</h2> +<p>See <a href="https://doc.rust-lang.org/book/ch04-03-slices.html#string-slices-as-parameters">https://doc.rust-lang.org/book/ch04-03-slices.html#string-slices-as-parameters</a> +In general, if you want to pass a reference to a string, use <code>&amp;str</code> instead of <code>&amp;String</code>.</p> +<h2 id="use-current-versions-of-dependencies">Use current versions of dependencies</h2> +<p>You can use <a href="https://crates.io/crates/cargo-upgrades">cargo upgrades</a> to check for outdated dependencies.</p> +<h2 id="if-your-project-has-separate-binaries-use-multiple-binaries-or-a-workspace">If your project has separate binaries, use multiple binaries or a workspace</h2> +<p>You can have multiple binaries in a single cargo project. Simply place them in the <code>src/bin</code> directory. +You can run them with <code>cargo run --bin &lt;name&gt;</code>. Alternatively, you can setup a +<a href="https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html">workspace</a>.</p> +<h2 id="run-clippy-cargo-fmt">Run clippy &amp; cargo fmt</h2> +<p>This should have become a habit by now. You can disable clippy warnings for a single item with <code>#[allow(clippy::...)]</code>, +but in most cases you shouldn't do that.</p> +<h2 id="if-you-need-to-escape-characters-in-a-string-use-raw-strings">If you need to escape characters in a string, use raw strings</h2> +<p>See <a href="https://doc.rust-lang.org/reference/tokens.html#raw-string-literals">https://doc.rust-lang.org/reference/tokens.html#raw-string-literals</a></p> +<h2 id="how-to-handle-errors">How to handle errors?</h2> +<p>Short: <a href="https://kerkour.com/rust-error-handling">https://kerkour.com/rust-error-handling</a></p> +<p>Long: <a href="https://www.lpalmieri.com/posts/error-handling-rust/">https://www.lpalmieri.com/posts/error-handling-rust/</a></p> +<h2 id="don-t-pass-around-locked-mutex-s-contents">Don't pass around locked mutex's contents</h2> +<p>If you have a mutex, you can use <code>lock()</code> to get a guard that will unlock the mutex when it goes out of scope. +But don't pass the contents of the guard to functions that can block (unless the mutex <em>must</em> be locked for +the entire duration of the function). +Instead of:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Mutex; +</span><span style="color:#8959a8;">use </span><span>std::thread; +</span><span style="color:#8959a8;">use </span><span>std::time::Duration; +</span><span style="color:#8959a8;">use </span><span>std::time::Instant; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">handle_function</span><span>(</span><span style="color:#f5871f;">counter</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut i32</span><span>) { +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> </span><span style="color:#3e999f;">*</span><span>counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= </span><span>Mutex::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> thread::scope(|</span><span style="color:#f5871f;">s</span><span>| { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= &amp;</span><span>counter; +</span><span> s.</span><span style="color:#4271ae;">spawn</span><span>(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> started&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> now </span><span style="color:#3e999f;">= </span><span>Instant::now(); +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">=</span><span> counter.</span><span style="color:#4271ae;">lock</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); +</span><span> </span><span style="color:#4271ae;">handle_function</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> counter); </span><span style="color:#999999;">// lock is held for 2 seconds +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> finished after </span><span style="color:#666969;">{}</span><span style="color:#718c00;">s&quot;</span><span>, now.</span><span style="color:#4271ae;">elapsed</span><span>().</span><span style="color:#4271ae;">as_secs</span><span>()); +</span><span> }); +</span><span> } +</span><span> }) +</span><span>} +</span></code></pre> +<p>You should do this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Mutex; +</span><span style="color:#8959a8;">use </span><span>std::thread; +</span><span style="color:#8959a8;">use </span><span>std::time::Duration; +</span><span style="color:#8959a8;">use </span><span>std::time::Instant; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">handle_function</span><span>(</span><span style="color:#f5871f;">counter</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>Mutex&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;) { </span><span style="color:#999999;">// &lt;-- changed +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">=</span><span> counter.</span><span style="color:#4271ae;">lock</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); </span><span style="color:#999999;">// &lt;-- changed +</span><span> </span><span style="color:#3e999f;">*</span><span>counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#999999;">// lock is held only for the duration of the block +</span><span> </span><span style="color:#999999;">// it is important to create a new scope here, otherwise the lock would be held for another second +</span><span> } +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= </span><span>Mutex::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> thread::scope(|</span><span style="color:#f5871f;">s</span><span>| { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= &amp;</span><span>counter; +</span><span> s.</span><span style="color:#4271ae;">spawn</span><span>(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> started&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> now </span><span style="color:#3e999f;">= </span><span>Instant::now(); +</span><span> </span><span style="color:#4271ae;">handle_function</span><span>(counter); </span><span style="color:#999999;">// &lt;-- changed! we don&#39;t lock here +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> finished after </span><span style="color:#666969;">{}</span><span style="color:#718c00;">s&quot;</span><span>, now.</span><span style="color:#4271ae;">elapsed</span><span>().</span><span style="color:#4271ae;">as_secs</span><span>()); +</span><span> }); +</span><span> } +</span><span> }) +</span><span>} +</span><span> +</span></code></pre> +<p>Compare the output of the two programs. The first one will take 20 seconds to finish, while the second one will take 2 seconds.</p> +<p>First one:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>Thread 1 started +</span><span>Thread 0 started +</span><span>Thread 2 started +</span><span>Thread 3 started +</span><span>Thread 4 started +</span><span>Thread 5 started +</span><span>Thread 6 started +</span><span>Thread 7 started +</span><span>Thread 8 started +</span><span>Thread 9 started +</span><span>Thread 1 finished after 2s +</span><span>Thread 0 finished after 4s +</span><span>Thread 2 finished after 6s +</span><span>Thread 3 finished after 8s +</span><span>Thread 4 finished after 10s +</span><span>Thread 5 finished after 12s +</span><span>Thread 6 finished after 14s +</span><span>Thread 7 finished after 16s +</span><span>Thread 8 finished after 18s +</span><span>Thread 9 finished after 20s +</span><span> +</span></code></pre> +<p>Second one:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>Thread 0 started +</span><span>Thread 2 started +</span><span>Thread 1 started +</span><span>Thread 3 started +</span><span>Thread 4 started +</span><span>Thread 5 started +</span><span>Thread 6 started +</span><span>Thread 7 started +</span><span>Thread 8 started +</span><span>Thread 9 started +</span><span>Thread 1 finished after 2s +</span><span>Thread 2 finished after 2s +</span><span>Thread 0 finished after 2s +</span><span>Thread 3 finished after 2s +</span><span>Thread 4 finished after 2s +</span><span>Thread 5 finished after 2s +</span><span>Thread 6 finished after 2s +</span><span>Thread 7 finished after 2s +</span><span>Thread 8 finished after 2s +</span><span>Thread 9 finished after 2s +</span></code></pre> + + + + + Project feedback + 2022-12-29T00:00:00+00:00 + 2022-12-29T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/12-project-feedback/ + + <h1 id="project-feedback">Project feedback</h1> +<h2 id="unwrapping-options-results">Unwrapping options/results</h2> +<p>Always ask yourself twice if you really need to unwrap. In most cases, you don't have to. Use pattern matching instead, +as it provides a static guarantee that the value is present.</p> +<p>Pattern matching prevents you from writing code like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">some_function</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">is_some</span><span>() { +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x.</span><span style="color:#4271ae;">unwrap</span><span>()); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Let&#39;s say this line was added later and/or you forgot to put it in the if statement. +</span><span> </span><span style="color:#4271ae;">do_something</span><span>(x.</span><span style="color:#4271ae;">unwrap</span><span>()); </span><span style="color:#999999;">// this will blow up if x == None! +</span><span>} +</span></code></pre> +<p>Instead, you can write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">some_function</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(x) </span><span style="color:#3e999f;">=</span><span> x { +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x); +</span><span> </span><span style="color:#4271ae;">do_something</span><span>(x); +</span><span> } +</span><span>} +</span></code></pre> +<h2 id="question-mark-operator">Question mark operator</h2> +<p>In methods that return <code>Result</code> or <code>Option</code>, you can use the question mark operator to return early if the value is <code>None</code> or <code>Err</code>. +See: <a href="https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html">https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html</a></p> +<h2 id="logging">Logging</h2> +<p>You can use the <a href="https://crates.io/crates/log">log</a> crate to log messages. It's better than <code>println!</code> because it +can be easily turned off. It also allows you to use different severity levels (e.g. <code>info</code>, <code>warn</code>, <code>error</code>) and only +log messages above a certain level.</p> +<h2 id="string-vs-str">&amp;String vs &amp;str</h2> +<p>See <a href="https://doc.rust-lang.org/book/ch04-03-slices.html#string-slices-as-parameters">https://doc.rust-lang.org/book/ch04-03-slices.html#string-slices-as-parameters</a> +In general, if you want to pass a reference to a string, use <code>&amp;str</code> instead of <code>&amp;String</code>.</p> +<h2 id="use-current-versions-of-dependencies">Use current versions of dependencies</h2> +<p>You can use <a href="https://crates.io/crates/cargo-upgrades">cargo upgrades</a> to check for outdated dependencies.</p> +<h2 id="if-your-project-has-separate-binaries-use-multiple-binaries-or-a-workspace">If your project has separate binaries, use multiple binaries or a workspace</h2> +<p>You can have multiple binaries in a single cargo project. Simply place them in the <code>src/bin</code> directory. +You can run them with <code>cargo run --bin &lt;name&gt;</code>. Alternatively, you can setup a +<a href="https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html">workspace</a>.</p> +<h2 id="run-clippy-cargo-fmt">Run clippy &amp; cargo fmt</h2> +<p>This should have become a habit by now. You can disable clippy warnings for a single item with <code>#[allow(clippy::...)]</code>, +but in most cases you shouldn't do that.</p> +<h2 id="if-you-need-to-escape-characters-in-a-string-use-raw-strings">If you need to escape characters in a string, use raw strings</h2> +<p>See <a href="https://doc.rust-lang.org/reference/tokens.html#raw-string-literals">https://doc.rust-lang.org/reference/tokens.html#raw-string-literals</a></p> +<h2 id="how-to-handle-errors">How to handle errors?</h2> +<p>Short: <a href="https://kerkour.com/rust-error-handling">https://kerkour.com/rust-error-handling</a></p> +<p>Long: <a href="https://www.lpalmieri.com/posts/error-handling-rust/">https://www.lpalmieri.com/posts/error-handling-rust/</a></p> +<h2 id="don-t-pass-around-locked-mutex-s-contents">Don't pass around locked mutex's contents</h2> +<p>If you have a mutex, you can use <code>lock()</code> to get a guard that will unlock the mutex when it goes out of scope. +But don't pass the contents of the guard to functions that can block (unless the mutex <em>must</em> be locked for +the entire duration of the function). +Instead of:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Mutex; +</span><span style="color:#8959a8;">use </span><span>std::thread; +</span><span style="color:#8959a8;">use </span><span>std::time::Duration; +</span><span style="color:#8959a8;">use </span><span>std::time::Instant; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">handle_function</span><span>(</span><span style="color:#f5871f;">counter</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut i32</span><span>) { +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> </span><span style="color:#3e999f;">*</span><span>counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= </span><span>Mutex::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> thread::scope(|</span><span style="color:#f5871f;">s</span><span>| { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= &amp;</span><span>counter; +</span><span> s.</span><span style="color:#4271ae;">spawn</span><span>(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> started&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> now </span><span style="color:#3e999f;">= </span><span>Instant::now(); +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">=</span><span> counter.</span><span style="color:#4271ae;">lock</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); +</span><span> </span><span style="color:#4271ae;">handle_function</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> counter); </span><span style="color:#999999;">// lock is held for 2 seconds +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> finished after </span><span style="color:#666969;">{}</span><span style="color:#718c00;">s&quot;</span><span>, now.</span><span style="color:#4271ae;">elapsed</span><span>().</span><span style="color:#4271ae;">as_secs</span><span>()); +</span><span> }); +</span><span> } +</span><span> }) +</span><span>} +</span></code></pre> +<p>You should do this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Mutex; +</span><span style="color:#8959a8;">use </span><span>std::thread; +</span><span style="color:#8959a8;">use </span><span>std::time::Duration; +</span><span style="color:#8959a8;">use </span><span>std::time::Instant; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">handle_function</span><span>(</span><span style="color:#f5871f;">counter</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>Mutex&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;) { </span><span style="color:#999999;">// &lt;-- changed +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">=</span><span> counter.</span><span style="color:#4271ae;">lock</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); </span><span style="color:#999999;">// &lt;-- changed +</span><span> </span><span style="color:#3e999f;">*</span><span>counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#999999;">// lock is held only for the duration of the block +</span><span> </span><span style="color:#999999;">// it is important to create a new scope here, otherwise the lock would be held for another second +</span><span> } +</span><span> thread::sleep(Duration::from_secs(</span><span style="color:#f5871f;">1</span><span>)); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= </span><span>Mutex::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> thread::scope(|</span><span style="color:#f5871f;">s</span><span>| { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> counter </span><span style="color:#3e999f;">= &amp;</span><span>counter; +</span><span> s.</span><span style="color:#4271ae;">spawn</span><span>(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> started&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> now </span><span style="color:#3e999f;">= </span><span>Instant::now(); +</span><span> </span><span style="color:#4271ae;">handle_function</span><span>(counter); </span><span style="color:#999999;">// &lt;-- changed! we don&#39;t lock here +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread </span><span style="color:#666969;">{i}</span><span style="color:#718c00;"> finished after </span><span style="color:#666969;">{}</span><span style="color:#718c00;">s&quot;</span><span>, now.</span><span style="color:#4271ae;">elapsed</span><span>().</span><span style="color:#4271ae;">as_secs</span><span>()); +</span><span> }); +</span><span> } +</span><span> }) +</span><span>} +</span><span> +</span></code></pre> +<p>Compare the output of the two programs. The first one will take 20 seconds to finish, while the second one will take 2 seconds.</p> +<p>First one:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>Thread 1 started +</span><span>Thread 0 started +</span><span>Thread 2 started +</span><span>Thread 3 started +</span><span>Thread 4 started +</span><span>Thread 5 started +</span><span>Thread 6 started +</span><span>Thread 7 started +</span><span>Thread 8 started +</span><span>Thread 9 started +</span><span>Thread 1 finished after 2s +</span><span>Thread 0 finished after 4s +</span><span>Thread 2 finished after 6s +</span><span>Thread 3 finished after 8s +</span><span>Thread 4 finished after 10s +</span><span>Thread 5 finished after 12s +</span><span>Thread 6 finished after 14s +</span><span>Thread 7 finished after 16s +</span><span>Thread 8 finished after 18s +</span><span>Thread 9 finished after 20s +</span><span> +</span></code></pre> +<p>Second one:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>Thread 0 started +</span><span>Thread 2 started +</span><span>Thread 1 started +</span><span>Thread 3 started +</span><span>Thread 4 started +</span><span>Thread 5 started +</span><span>Thread 6 started +</span><span>Thread 7 started +</span><span>Thread 8 started +</span><span>Thread 9 started +</span><span>Thread 1 finished after 2s +</span><span>Thread 2 finished after 2s +</span><span>Thread 0 finished after 2s +</span><span>Thread 3 finished after 2s +</span><span>Thread 4 finished after 2s +</span><span>Thread 5 finished after 2s +</span><span>Thread 6 finished after 2s +</span><span>Thread 7 finished after 2s +</span><span>Thread 8 finished after 2s +</span><span>Thread 9 finished after 2s +</span></code></pre> + + + + + Async: Part 1 + 2022-12-12T00:00:00+00:00 + 2022-12-12T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/11-async-1/ + + <h2 id="tokio">Tokio</h2> +<p>We'll use the <a href="https://tokio.rs/tokio/tutorial">Tokio tutorial</a> (chapters <code>Overview</code>-<code>Channels</code>).</p> +<h2 id="common-rust-lifetime-misconceptions">Common Rust Lifetime Misconceptions</h2> +<p>Please read <a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md">this blogpost</a>.</p> + + + + + Design patterns + 2022-12-05T00:00:00+00:00 + 2022-12-05T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/10-design-patterns/ + + <h2 id="object-oriented-programming-and-rust">Object-oriented programming and Rust</h2> +<p>The book has <a href="https://doc.rust-lang.org/stable/book/ch17-01-what-is-oo.html">a chapter dedicated to it</a>. +Especially the <a href="https://doc.rust-lang.org/stable/book/ch17-03-oo-design-patterns.html#encoding-states-and-behavior-as-types">&quot;typestate&quot;</a> pattern is very interesting. +You can read more about it <a href="http://cliffle.com/blog/rust-typestate/">here</a>.</p> +<h2 id="how-to-build-a-good-library">How to build a good library</h2> +<p><a href="https://rust-lang.github.io/api-guidelines/about.html">These guidelines</a> have been created by the Rust library team.</p> +<h2 id="how-to-handle-errors">How to handle errors</h2> +<p><a href="https://nick.groenen.me/posts/rust-error-handling/">This post</a> is from 2020, but the libraries it mentions (<code>anyhow</code> and <code>thiserror</code>) are still the most popular.</p> +<h2 id="serde">Serde</h2> +<p><a href="https://serde.rs/">Serde</a> is the most popular serialization library for Rust.</p> +<h2 id="assignment">Assignment</h2> +<p>This week's assignment is to write a &quot;distributed&quot; calculator. +You should base your solution on the <a href="https://doc.rust-lang.org/stable/book/ch20-00-final-project-a-web-server.html">final project from the book</a>.</p> + + + + + Design patterns + 2022-12-05T00:00:00+00:00 + 2022-12-05T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/10-design-patterns/ + + <h2 id="object-oriented-programming-and-rust">Object-oriented programming and Rust</h2> +<p>The book has <a href="https://doc.rust-lang.org/stable/book/ch17-01-what-is-oo.html">a chapter dedicated to it</a>. +Especially the <a href="https://doc.rust-lang.org/stable/book/ch17-03-oo-design-patterns.html#encoding-states-and-behavior-as-types">&quot;typestate&quot;</a> pattern is very interesting. +You can read more about it <a href="http://cliffle.com/blog/rust-typestate/">here</a>.</p> +<h2 id="how-to-build-a-good-library">How to build a good library</h2> +<p><a href="https://rust-lang.github.io/api-guidelines/about.html">These guidelines</a> have been created by the Rust library team.</p> +<h2 id="how-to-handle-errors">How to handle errors</h2> +<p><a href="https://nick.groenen.me/posts/rust-error-handling/">This post</a> is from 2020, but the libraries it mentions (<code>anyhow</code> and <code>thiserror</code>) are still the most popular.</p> +<h2 id="serde">Serde</h2> +<p><a href="https://serde.rs/">Serde</a> is the most popular serialization library for Rust.</p> +<h2 id="assignment">Assignment</h2> +<p>This week's assignment is to write a &quot;distributed&quot; calculator. +You should base your solution on the <a href="https://doc.rust-lang.org/stable/book/ch20-00-final-project-a-web-server.html">final project from the book</a>.</p> + + + + + Fearless concurrency + 2022-11-28T00:00:00+00:00 + 2022-11-28T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/09-concurrency/ + + <h2 id="parallelism-vs-concurrency">Parallelism vs Concurrency</h2> +<p>Concurrency is when tasks <strong>can make</strong> progress <strong>independently</strong> of each other.</p> +<p>Parallelism is when multiple tasks <strong>make</strong> progress <strong>at the same time</strong>.</p> +<h2 id="concurrency-models-in-rust">Concurrency models in Rust</h2> +<h3 id="threads">Threads</h3> +<p>Nothing unusual here.</p> +<p>Threads can be created with the <code>thread::spawn</code> function <a href="https://doc.rust-lang.org/std/thread/fn.spawn.html">docs - please read them!</a>.</p> +<p>This method returns a <code>JoinHandle&lt;T&gt;</code> which can be used to wait for the thread to finish. <code>T</code> is the type of the thread's return value.</p> +<h4 id="propagating-panics">Propagating panics</h4> +<p>In Rust a panic of one thread doesn't affect the other threads (similar to how Java handles exceptions in threads).</p> +<h4 id="closures">Closures</h4> +<p>Closures which are used to create threads must take ownership of any values they use. It can be forced with the <code>move</code> keyword.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::thread; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> v </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> handle </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Here&#39;s a vector: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, v); +</span><span> }); +</span><span> +</span><span> handle.</span><span style="color:#4271ae;">join</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); +</span><span>} +</span></code></pre> +<p>Normal ownership rules still apply. It means that we cannot mutate the vector in the spawned thread from the main thread!</p> +<p>But what if we need to share some state?</p> +<h3 id="message-passing">Message passing</h3> +<p>One possible way is to use message passing. We can use a blocking queue (called <code>mpsc</code> - <a href="https://doc.rust-lang.org/std/sync/mpsc/index.html">&quot;multi producer single consumer FIFO queue&quot;</a>) to do it. +We talked about blocking queues in the Concurrent programming class. In Rust, they are strongly-typed. Sending and receiving ends have different types.</p> +<h3 id="mutexes">Mutexes</h3> +<p>In Rust, a mutex <em>wraps</em> a value and makes it thread-safe. +Because it becomes a part of the type, it's impossible to access the underlying value in an unsynchronized manner. It is conceptually similar to the <code>RefCell</code> type.</p> +<p><code>Arc</code> is a smart pointer like <code>Rc</code> but it can be shared between threads.</p> +<p>Please read more about them in <a href="https://doc.rust-lang.org/stable/book/ch16-03-shared-state.html">the book</a>.</p> +<p><a href="https://doc.rust-lang.org/std/sync/struct.Mutex.html">The docs</a> also mention <code>poisoning</code>.</p> +<h3 id="rwlocks">RwLocks</h3> +<p><a href="https://doc.rust-lang.org/std/sync/struct.RwLock.html">RwLocks</a> are similar to mutexes, but they distinguish between read and write locks.</p> +<h2 id="send-and-sync">Send and Sync</h2> +<p>They are marker traits used to indicate that a type or a reference to it can be sent across threads. See the <a href="https://doc.rust-lang.org/nomicon/send-and-sync.html">nomicon</a> for more information.</p> +<h2 id="atomic-types">Atomic types</h2> +<p>Atomic types are described in <a href="https://doc.rust-lang.org/std/sync/atomic/">the docs</a>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Arc; +</span><span style="color:#8959a8;">use </span><span>std::sync::atomic::{AtomicUsize, Ordering}; +</span><span style="color:#8959a8;">use </span><span>std::{hint, thread}; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(AtomicUsize::new(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span> </span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> spinlock_clone.</span><span style="color:#4271ae;">store</span><span>(</span><span style="color:#f5871f;">0</span><span>, Ordering::SeqCst); +</span><span> }); +</span><span> +</span><span> </span><span style="color:#999999;">// Wait for the other thread to release the lock +</span><span> </span><span style="color:#8959a8;">while</span><span> spinlock.</span><span style="color:#4271ae;">load</span><span>(Ordering::SeqCst) </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Err</span><span>(panic) </span><span style="color:#3e999f;">=</span><span> thread.</span><span style="color:#4271ae;">join</span><span>() { +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread had an error: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, panic); +</span><span> } +</span><span>} +</span></code></pre> +<p>Note that <code>atomic</code> values don't have to be wrapped in a mutex when shared across threads.</p> +<h3 id="wait">Wait...</h3> +<p>If most types are <code>Sync + Send</code>, then what stops us from using a standard, non-atomic integer in the example above?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>spinlock_clone </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>}); +</span><span> +</span><span style="color:#8959a8;">while </span><span style="color:#3e999f;">*</span><span>spinlock </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span>} +</span></code></pre> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0594]: cannot assign to data in an `Arc` +</span><span> --&gt; src/main.rs:9:9 +</span><span> | +</span><span>9 | *spinlock_clone += 1; +</span><span> | ^^^^^^^^^^^^^^^^^^^^ cannot assign +</span><span> | +</span><span> = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc&lt;i32&gt;` +</span></code></pre> +<p>...so we would have to use a <code>RefCell</code> to be able to modify the value through a shared reference...</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(RefCell::new(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> +</span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>spinlock_clone.</span><span style="color:#4271ae;">borrow_mut</span><span>() </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>}); +</span><span> +</span><span style="color:#999999;">// Wait for the other thread to release the lock +</span><span style="color:#8959a8;">while </span><span style="color:#3e999f;">*</span><span>spinlock.</span><span style="color:#4271ae;">borrow</span><span>() </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span>} +</span></code></pre> +<p>...but <code>RefCell</code> isn't <code>Sync</code>:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0277]: `RefCell&lt;i32&gt;` cannot be shared between threads safely +</span><span> --&gt; src/main.rs:9:18 +</span><span> | +</span><span>9 | let thread = thread::spawn(move|| { +</span><span> | ^^^^^^^^^^^^^ `RefCell&lt;i32&gt;` cannot be shared between threads safely +</span><span> | +</span><span> = help: the trait `Sync` is not implemented for `RefCell&lt;i32&gt;` +</span><span> = note: required because of the requirements on the impl of `Send` for `Arc&lt;RefCell&lt;i32&gt;&gt;` +</span><span> = note: required because it appears within the type `[closure@src/main.rs:9:32: 11:6]` +</span><span>note: required by a bound in `spawn` +</span></code></pre> +<p>And that bound mentioned in the last line looks like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">spawn</span><span>&lt;F, T&gt;(</span><span style="color:#f5871f;">f</span><span>: F) -&gt; JoinHandle&lt;T&gt; </span><span style="color:#8959a8;">where +</span><span> F: FnOnce() -&gt; T, +</span><span> F: Send + </span><span style="color:#8959a8;">&#39;static</span><span>, +</span><span> T: Send + </span><span style="color:#8959a8;">&#39;static</span><span>, +</span></code></pre> +<h4 id="exercise-for-the-reader">Exercise for the reader</h4> +<p>Why is it impossible to share a reference to a <code>Mutex</code> between threads?</p> +<h2 id="data-parallelism-with-rayon">Data parallelism with Rayon</h2> +<p><a href="https://docs.rs/rayon/latest/rayon/">Rayon</a> is a library for parallelization of data processing. +It can be used to parallelize the execution of functions over a collection of data by switching the standard <code>Iterator</code> to a <code>ParallelIterator</code>. +It works very similar to <a href="https://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html#executing_streams_in_parallel">Java's parallel streams</a>.</p> +<p>Why do that? Because thread synchronization is hard! <a href="https://doc.rust-lang.org/nomicon/races.html">Rust prevents data races</a>, but <a href="https://users.rust-lang.org/t/deadlock-is-it-a-bug-or-is-it-intentional/1544">logical races and deadlocks are impossible to prevent!</a>!</p> +<p><a href="https://github.com/rayon-rs/rayon/blob/master/FAQ.md">Rayon's FAQ</a> is worth reading.</p> +<h2 id="reading">Reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/book/ch16-00-concurrency.html">The Book</a></li> +<li><a href="http://archive.today/WFlZV">Safely writing code that isn't thread-safe</a></li> +</ul> + + + + + Smart Pointers + 2022-11-21T00:00:00+00:00 + 2022-11-21T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/07-smart-pointers/ + + <h1 id="working-with-the-heap">Working with the heap</h1> +<p>So far we've only used heap allocated memory indirectly by working with containers such as vectors, maps or the <code>String</code> type, otherwise allocating our variables on the stack. We didn't really have to be aware of the fact that these collections used the heap, as all that memory management details were hidden away from us. In this lesson we'll take a closer look at what is really happening there and how we can do that ourselves.</p> +<p>To work with heap-allocated memory, Rust features <em>smart pointers</em>. You should have already heard this term as it is a very important feature in C++ and the concept is virtually the same here - they are wrappers around raw allocated memory that provide additional, safety-ensuring mechanism. What defines a smart pointer in Rust is generally the implementation of two traits: <code>Drop</code> and <code>Deref</code>.</p> +<p>The <code>Drop</code> trait is pretty straightforward as it consists of one method - <code>fn drop(&amp;mut self)</code> - that is, basically, the destructor, invoked during stack unwinding.</p> +<p>The <code>Deref</code> trait allows us to overload the dereference (<code>*</code>) operator.</p> +<h2 id="deref-coercion">Deref coercion</h2> +<p>Apart from enabling access to the underlying value, implementing the <code>Deref</code> trait enables Rust to perform <em>deref coercion</em> on the pointer - trying to remove as many levels of indirection as it can. What it means in practice is that we will be able to use it with any code working on plain references.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::ops::Deref; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>MyBox&lt;T&gt;(T); +</span><span> +</span><span style="color:#999999;">// We won&#39;t be allocating anything on the heap here as it is not important here. +</span><span style="color:#999999;">// We&#39;re only focusing on the dereference mechanisms. +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; MyBox&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: T) -&gt; MyBox&lt;T&gt; { +</span><span> MyBox(x) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; Deref </span><span style="color:#8959a8;">for </span><span>MyBox&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Target </span><span style="color:#3e999f;">=</span><span> T; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">deref</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">Self::</span><span>Target { +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0 +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#f5871f;">name</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;Hello, </span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, name); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> int_box </span><span style="color:#3e999f;">= </span><span>MyBox::new(x); +</span><span> +</span><span> assert_eq!(</span><span style="color:#f5871f;">5</span><span>, </span><span style="color:#3e999f;">*</span><span>int_box); +</span><span> +</span><span> </span><span style="color:#999999;">// String also implements the `Deref` trait. +</span><span> </span><span style="color:#999999;">// In fact, String actually is a smart pointer. +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;I&#39;m a smart pointer too&quot;</span><span>); +</span><span> </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> +</span><span> </span><span style="color:#999999;">// Deref coercion can deal with multiple levels of indirection. +</span><span> </span><span style="color:#8959a8;">let</span><span> str_box </span><span style="color:#3e999f;">= </span><span>MyBox::new(</span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Rust&quot;</span><span>)); +</span><span> </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>str_box); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/07-smart-pointers/deref_coercion.rs">deref_coercion.rs</a>)</sub></p> +<p>In general, there are three possible coercions that Rust can perform:</p> +<ul> +<li> +<p>From <code>&amp;T</code> to <code>&amp;U</code> when <code>T: Deref&lt;Target=U&gt;</code></p> +</li> +<li> +<p>From <code>&amp;mut T</code> to <code>&amp;mut U</code> when <code>T: DerefMut&lt;Target=U&gt;</code></p> +</li> +<li> +<p>From <code>&amp;mut T</code> to <code>&amp;U</code> when <code>T: Deref&lt;Target=U&gt;</code></p> +</li> +</ul> +<p>While the first two coercions are straightforward, the third one is possible because treating a mutable reference as an immutable one does not break the rules of ownership.</p> +<h1 id="box-simple-wrapper"><code>Box</code> - simple wrapper</h1> +<p>The <code>Box&lt;T&gt;</code> type is the most basic out of Rust's smart pointers, equivalent to C++'s <code>std::unique_ptr&lt;T&gt;</code>. It's a simple wrapper that makes sure the underlying memory gets allocated and freed properly.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">box_simple</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> b </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Box</span><span>::new(</span><span style="color:#f5871f;">5</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;b = </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, b); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">10 </span><span style="color:#3e999f;">+ *</span><span>b; +</span><span>} +</span><span> +</span><span style="color:#999999;">// `Box` gives us the indirection required to define +</span><span style="color:#999999;">// recursive types +</span><span>#[</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span style="color:#8959a8;">enum </span><span>List { +</span><span> Cons(</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#c99e00;">Box</span><span>&lt;List&gt;), +</span><span> Nil, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#4271ae;">box_simple</span><span>(); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/07-smart-pointers/box.rs">box.rs</a>)</sub></p> +<h1 id="reference-counting">Reference counting</h1> +<p>The <code>Rc&lt;T&gt;</code> type is the equivalent of <code>std::shared_ptr&lt;T&gt;</code> from C++. There is one caveat to this though - because we're creating multiple references to the same object, those references have to be immutable in accordance with the ownership rules.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::rc::Rc; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>LoudInt(</span><span style="color:#8959a8;">i32</span><span>); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Drop </span><span style="color:#8959a8;">for </span><span>LoudInt { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">drop</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[</span><span style="color:#666969;">{}</span><span style="color:#718c00;">] Farewell!&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> outer_ref; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> inner_ref </span><span style="color:#3e999f;">= </span><span>Rc::new(LoudInt(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// strong_count represents the number of owning references pointing +</span><span> </span><span style="color:#999999;">// to data +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> outer_ref </span><span style="color:#3e999f;">= </span><span>Rc::clone(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref); +</span><span> +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>outer_ref)); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), </span><span style="color:#f5871f;">2</span><span>); +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;The </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> still lives!&quot;</span><span>, outer_ref.</span><span style="color:#f5871f;">0</span><span>); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>outer_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/07-smart-pointers/ref_count.rs">ref_count.rs</a>)</sub></p> +<p>Rust also provides a non-owning pointer in the form of <code>Weak&lt;T&gt;</code> (equivalent to <code>std::weak_ptr&lt;T&gt;</code>) that can be obtained from an instance of <code>Rc&lt;T&gt;</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::rc::Rc; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>LoudInt(</span><span style="color:#8959a8;">i32</span><span>); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Drop </span><span style="color:#8959a8;">for </span><span>LoudInt { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">drop</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[</span><span style="color:#666969;">{}</span><span style="color:#718c00;">] Farewell!&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> weak_ref; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> shared_ref </span><span style="color:#3e999f;">= </span><span>Rc::new(LoudInt(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// weak_count keeps track of the non-owning reference to the data +</span><span> assert_eq!(Rc::weak_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">0</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// `downgrade()` obtains a weak pointer to Rc&#39;s data +</span><span> weak_ref </span><span style="color:#3e999f;">= </span><span>Rc::downgrade(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref); +</span><span> +</span><span> assert_eq!(Rc::weak_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// In order to use the the data underneath the weak pointer +</span><span> </span><span style="color:#999999;">// we need to obtain a new shared pointer from it. +</span><span> </span><span style="color:#999999;">// The `upgrade()` method returns `Option&lt;Rc&lt;T&gt;&gt;`. +</span><span> </span><span style="color:#8959a8;">let</span><span> temp </span><span style="color:#3e999f;">=</span><span> weak_ref.</span><span style="color:#4271ae;">upgrade</span><span>(); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">2</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;The value is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, temp.</span><span style="color:#4271ae;">unwrap</span><span>().</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;The value should be deallocated by now.&quot;</span><span>); +</span><span> assert!(weak_ref.</span><span style="color:#4271ae;">upgrade</span><span>().</span><span style="color:#4271ae;">is_none</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/07-smart-pointers/weak_ref.rs">weak_ref.rs</a>)</sub></p> +<h1 id="mutating-the-immutable">Mutating the immutable</h1> +<p>Good examples and explanation of the interior mutability pattern and runtime borrow checking can be found in the <a href="https://doc.rust-lang.org/book/ch15-05-interior-mutability.html">book</a>.</p> +<p>Alongside the <code>RefCell&lt;T&gt;</code> type described above, there is an analogous <a href="https://doc.rust-lang.org/std/cell/struct.Cell.html"><code>Cell&lt;T&gt;</code></a> type that operates on values instead of references.</p> +<h1 id="convenient-handling-of-dyn-objects">Convenient handling of <code>dyn</code> objects</h1> +<p>In previous labs you learned about dynamic dispatch and its strengths. The largest drawback you noticed is most likely that they are <em>unsized</em> (<code>!Sized</code>, where <code>!</code> being syntax signifying lack of trait implementation).</p> +<p>When storing an object on a heap, however, we can use it as a <code>dyn</code> object seamlessly.</p> +<h1 id="obligatory-reading">Obligatory reading</h1> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch15-00-smart-pointers.html">The Book, chapter 15</a></p> +</li> +<li> +<p><a href="https://doc.rust-lang.org/std/borrow/enum.Cow.html">std::borrow::Cow</a>, a versatile copy-on-write smart pointer</p> +</li> +</ul> +<h1 id="additional-reading">Additional reading</h1> +<ul> +<li><a href="https://www.fpcomplete.com/blog/rust-asref-asderef/">On wrapped references</a></li> +<li><a href="https://dev.to/zhanghandong/rust-concept-clarification-deref-vs-asref-vs-borrow-vs-cow-13g6"><code>Deref</code> vs <code>AsRef</code> vs <code>Borrow</code></a></li> +</ul> +<h2 id="assignment-5-graded">Assignment 5 (graded)</h2> +<p><a href="https://classroom.github.com/a/QlO3aCCP">Corporations</a></p> +<p>Deadline: 13.11.2024 23:59</p> + + + + + Feedback #2 + 2022-11-21T00:00:00+00:00 + 2022-11-21T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/08-feedback-2/ + + <h2 id="feedback">Feedback</h2> +<h3 id="conditional-implementation">Conditional implementation</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">const</span><span> N: </span><span style="color:#8959a8;">usize</span><span>&gt; Shape </span><span style="color:#8959a8;">for </span><span>SphereN&lt;N&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Volume </span><span style="color:#3e999f;">= </span><span>VolumeN&lt;N&gt;; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">volume</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Volume { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> volume: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span>(</span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) </span><span style="color:#3e999f;">* </span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) </span><span style="color:#3e999f;">* </span><span style="color:#666969;">PI</span><span>) </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u32</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> N </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">3 </span><span>{ +</span><span> volume </span><span style="color:#3e999f;">= </span><span>(</span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#666969;">PI +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">4.0_</span><span style="color:#8959a8;">f64 +</span><span> </span><span style="color:#3e999f;">/ </span><span style="color:#f5871f;">3.0_</span><span style="color:#8959a8;">f64</span><span>) </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u32</span><span>; +</span><span> } +</span><span> </span><span style="color:#8959a8;">Self</span><span>::Volume::new(volume) +</span><span> } +</span><span>} +</span></code></pre> +<p>Instead of checking <code>N == 3</code>, you can provide different impls for <code>SphereN&lt;2&gt;</code> and +<code>SphereN&lt;3&gt;</code> (as they are different types).</p> +<h3 id="u32-and-u64">u32 and u64</h3> +<p>They <em>are</em> different types, but because you can easily cast one to another, +it was not sufficient to make the implementation type-safe.</p> + + + + + Smart Pointers + 2022-11-21T00:00:00+00:00 + 2022-11-21T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/07-smart-pointers/ + + <h1 id="working-with-the-heap">Working with the heap</h1> +<p>So far we've only used heap allocated memory indirectly by working with containers such as vectors, maps or the <code>String</code> type, otherwise allocating our variables on the stack. We didn't really have to be aware of the fact that these collections used the heap, as all that memory management details were hidden away from us. In this lesson we'll take a closer look at what is really happening there and how we can do that ourselves.</p> +<p>To work with heap-allocated memory, Rust features <em>smart pointers</em>. You should have already heard this term as it is a very important feature in C++ and the concept is virtually the same here - they are wrappers around raw allocated memory that provide additional, safety-ensuring mechanism. What defines a smart pointer in Rust is generally the implementation of two traits: <code>Drop</code> and <code>Deref</code>.</p> +<p>The <code>Drop</code> trait is pretty straightforward as it consists of one method - <code>fn drop(&amp;mut self)</code> - that is, basically, the destructor, invoked during stack unwinding.</p> +<p>The <code>Deref</code> trait allows us to overload the dereference (<code>*</code>) operator.</p> +<h2 id="deref-coercion">Deref coercion</h2> +<p>Apart from enabling access to the underlying value, implementing the <code>Deref</code> trait enables Rust to perform <em>deref coercion</em> on the pointer - trying to remove as many levels of indirection as it can. What it means in practice is that we will be able to use it with any code working on plain references.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::ops::Deref; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>MyBox&lt;T&gt;(T); +</span><span> +</span><span style="color:#999999;">// We won&#39;t be allocating anything on the heap here as it is not important here. +</span><span style="color:#999999;">// We&#39;re only focusing on the dereference mechanisms. +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; MyBox&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: T) -&gt; MyBox&lt;T&gt; { +</span><span> MyBox(x) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; Deref </span><span style="color:#8959a8;">for </span><span>MyBox&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Target </span><span style="color:#3e999f;">=</span><span> T; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">deref</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">Self::</span><span>Target { +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0 +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#f5871f;">name</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;Hello, </span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, name); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> int_box </span><span style="color:#3e999f;">= </span><span>MyBox::new(x); +</span><span> +</span><span> assert_eq!(</span><span style="color:#f5871f;">5</span><span>, </span><span style="color:#3e999f;">*</span><span>int_box); +</span><span> +</span><span> </span><span style="color:#999999;">// String also implements the `Deref` trait. +</span><span> </span><span style="color:#999999;">// In fact, String actually is a smart pointer. +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;I&#39;m a smart pointer too&quot;</span><span>); +</span><span> </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> +</span><span> </span><span style="color:#999999;">// Deref coercion can deal with multiple levels of indirection. +</span><span> </span><span style="color:#8959a8;">let</span><span> str_box </span><span style="color:#3e999f;">= </span><span>MyBox::new(</span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Rust&quot;</span><span>)); +</span><span> </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>str_box); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/07-smart-pointers/deref_coercion.rs">deref_coercion.rs</a>)</sub></p> +<p>In general, there are three possible coercions that Rust can perform:</p> +<ul> +<li> +<p>From <code>&amp;T</code> to <code>&amp;U</code> when <code>T: Deref&lt;Target=U&gt;</code></p> +</li> +<li> +<p>From <code>&amp;mut T</code> to <code>&amp;mut U</code> when <code>T: DerefMut&lt;Target=U&gt;</code></p> +</li> +<li> +<p>From <code>&amp;mut T</code> to <code>&amp;U</code> when <code>T: Deref&lt;Target=U&gt;</code></p> +</li> +</ul> +<p>While the first two coercions are straightforward, the third one is possible because treating a mutable reference as an immutable one does not break the rules of ownership.</p> +<h1 id="box-simple-wrapper"><code>Box</code> - simple wrapper</h1> +<p>The <code>Box&lt;T&gt;</code> type is the most basic out of Rust's smart pointers, equivalent to C++'s <code>std::unique_ptr&lt;T&gt;</code>. It's a simple wrapper that makes sure the underlying memory gets allocated and freed properly.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">box_simple</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> b </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Box</span><span>::new(</span><span style="color:#f5871f;">5</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;b = </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, b); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">10 </span><span style="color:#3e999f;">+ *</span><span>b; +</span><span>} +</span><span> +</span><span style="color:#999999;">// `Box` gives us the indirection required to define +</span><span style="color:#999999;">// recursive types +</span><span>#[</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span style="color:#8959a8;">enum </span><span>List { +</span><span> Cons(</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#c99e00;">Box</span><span>&lt;List&gt;), +</span><span> Nil, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#4271ae;">box_simple</span><span>(); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/07-smart-pointers/box.rs">box.rs</a>)</sub></p> +<h1 id="reference-counting">Reference counting</h1> +<p>The <code>Rc&lt;T&gt;</code> type is the equivalent of <code>std::shared_ptr&lt;T&gt;</code> from C++. There is one caveat to this though - because we're creating multiple references to the same object, those references have to be immutable in accordance with the ownership rules.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::rc::Rc; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>LoudInt(</span><span style="color:#8959a8;">i32</span><span>); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Drop </span><span style="color:#8959a8;">for </span><span>LoudInt { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">drop</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[</span><span style="color:#666969;">{}</span><span style="color:#718c00;">] Farewell!&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> outer_ref; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> inner_ref </span><span style="color:#3e999f;">= </span><span>Rc::new(LoudInt(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// strong_count represents the number of owning references pointing +</span><span> </span><span style="color:#999999;">// to data +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> outer_ref </span><span style="color:#3e999f;">= </span><span>Rc::clone(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref); +</span><span> +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>outer_ref)); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), </span><span style="color:#f5871f;">2</span><span>); +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;The </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> still lives!&quot;</span><span>, outer_ref.</span><span style="color:#f5871f;">0</span><span>); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>outer_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/07-smart-pointers/ref_count.rs">ref_count.rs</a>)</sub></p> +<p>Rust also provides a non-owning pointer in the form of <code>Weak&lt;T&gt;</code> (equivalent to <code>std::weak_ptr&lt;T&gt;</code>) that can be obtained from an instance of <code>Rc&lt;T&gt;</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::rc::Rc; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>LoudInt(</span><span style="color:#8959a8;">i32</span><span>); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Drop </span><span style="color:#8959a8;">for </span><span>LoudInt { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">drop</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[</span><span style="color:#666969;">{}</span><span style="color:#718c00;">] Farewell!&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> weak_ref; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> shared_ref </span><span style="color:#3e999f;">= </span><span>Rc::new(LoudInt(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// weak_count keeps track of the non-owning reference to the data +</span><span> assert_eq!(Rc::weak_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">0</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// `downgrade()` obtains a weak pointer to Rc&#39;s data +</span><span> weak_ref </span><span style="color:#3e999f;">= </span><span>Rc::downgrade(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref); +</span><span> +</span><span> assert_eq!(Rc::weak_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// In order to use the the data underneath the weak pointer +</span><span> </span><span style="color:#999999;">// we need to obtain a new shared pointer from it. +</span><span> </span><span style="color:#999999;">// The `upgrade()` method returns `Option&lt;Rc&lt;T&gt;&gt;`. +</span><span> </span><span style="color:#8959a8;">let</span><span> temp </span><span style="color:#3e999f;">=</span><span> weak_ref.</span><span style="color:#4271ae;">upgrade</span><span>(); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">2</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;The value is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, temp.</span><span style="color:#4271ae;">unwrap</span><span>().</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;The value should be deallocated by now.&quot;</span><span>); +</span><span> matches!(weak_ref.</span><span style="color:#4271ae;">upgrade</span><span>(), </span><span style="color:#c99e00;">None</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/07-smart-pointers/weak_ref.rs">weak_ref.rs</a>)</sub></p> +<h1 id="mutating-the-immutable">Mutating the immutable</h1> +<p>Good examples and explanation of the inferior mutability pattern and runtime borrow checking can be found in the <a href="https://doc.rust-lang.org/book/ch15-05-interior-mutability.html">book</a>.</p> +<p>Alongisde the <code>RefCell&lt;T&gt;</code> type described above, there is an analogous <a href="https://doc.rust-lang.org/std/cell/struct.Cell.html"><code>Cell&lt;T&gt;</code></a> type that operates on values instead of references.</p> +<h1 id="obligatory-reading">Obligatory reading</h1> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch15-00-smart-pointers.html">The Book, chapter 15</a></p> +</li> +<li> +<p><a href="https://doc.rust-lang.org/std/borrow/enum.Cow.html">std::borrow::Cow</a>, a versatile copy-on-write smart pointer</p> +</li> +</ul> +<h1 id="additional-reading">Additional reading</h1> +<ul> +<li><a href="https://www.fpcomplete.com/blog/rust-asref-asderef/">On wrapped references</a></li> +</ul> + + + + + Feedback #2 + 2022-11-21T00:00:00+00:00 + 2022-11-21T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/08-feedback-2/ + + <h2 id="feedback">Feedback</h2> +<h3 id="conditional-implementation">Conditional implementation</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">const</span><span> N: </span><span style="color:#8959a8;">usize</span><span>&gt; Shape </span><span style="color:#8959a8;">for </span><span>SphereN&lt;N&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Volume </span><span style="color:#3e999f;">= </span><span>VolumeN&lt;N&gt;; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">volume</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Volume { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> volume: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span>(</span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) </span><span style="color:#3e999f;">* </span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) </span><span style="color:#3e999f;">* </span><span style="color:#666969;">PI</span><span>) </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u32</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> N </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">3 </span><span>{ +</span><span> volume </span><span style="color:#3e999f;">= </span><span>(</span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#8959a8;">f64</span><span>::from(</span><span style="color:#c82829;">self</span><span>.radius) +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#666969;">PI +</span><span> </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">4.0_</span><span style="color:#8959a8;">f64 +</span><span> </span><span style="color:#3e999f;">/ </span><span style="color:#f5871f;">3.0_</span><span style="color:#8959a8;">f64</span><span>) </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u32</span><span>; +</span><span> } +</span><span> </span><span style="color:#8959a8;">Self</span><span>::Volume::new(volume) +</span><span> } +</span><span>} +</span></code></pre> +<p>Instead of checking <code>N == 3</code>, you can provide different impls for <code>SphereN&lt;2&gt;</code> and +<code>SphereN&lt;3&gt;</code> (as they are different types).</p> +<h3 id="u32-and-u64">u32 and u64</h3> +<p>They <em>are</em> different types, but because you can easily cast one to another, +it was not sufficient to make the implementation type-safe.</p> + + + + + Closures and Iterators + 2022-11-14T00:00:00+00:00 + 2022-11-14T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/06-closures-iterators/ + + <h1 id="closures">Closures</h1> +<p>Closures (Polish: &quot;domknięcia&quot;) are anonymous functions that can access variables from the scope in which they were defined.</p> +<p>We'll go through the examples from <a href="https://doc.rust-lang.org/rust-by-example/fn/closures.html">Rust by Example</a>.</p> +<h1 id="iterators">Iterators</h1> +<p>In Rust, there is no hierarchy of types for collections (because there is no inheritance in general). +Instead, what makes a collection is that it can be iterated over.</p> +<p>We'll go through the official <a href="https://doc.rust-lang.org/stable/std/iter/">docs</a>. +Most methods are defined in the <a href="https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html">Iterator trait</a>.</p> +<h1 id="reading">Reading</h1> +<ul> +<li><a href="https://doc.rust-lang.org/book/ch12-00-an-io-project.html">The Book, chapter 12 (that's a project!)</a></li> +<li><a href="https://doc.rust-lang.org/book/ch13-00-functional-features.html">The Book, chapter 13</a></li> +<li><a href="https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html">The Book, chapter 14</a></li> +<li><a href="https://doc.rust-lang.org/stable/book/ch19-05-advanced-functions-and-closures.html">The Book, Advanced Functions and Closures</a></li> +<li><a href="https://doc.rust-lang.org/stable/book/ch19-03-advanced-traits.html">The Book, Advanced Traits</a></li> +</ul> + + + + + Reasoning About Types + 2022-11-07T00:00:00+00:00 + 2022-11-07T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/ + + <h1 id="type-traits">Type traits</h1> +<p>Traits are a way to defined common behavior between different types. They can be compared to <em>interfaces</em> from many other mainstream languages or to typeclasses from Haskell, however, Rust is not an object-oriented language and there are some notable differences between type traits and Java interfaces.</p> +<p>The way we describe behavior in Rust is through methods. Traits consist of a set of these methods which then should be implemented by a type. We've already encountered examples of these, like the <code>Clone</code> trait which specified that the <code>clone()</code> method can be called on some given type. Now, let's take a deeper look and try defining our own trait.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Summary { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.username, </span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.</span><span style="color:#4271ae;">summarize</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/basic_trait.rs">basic_trait.rs</a>)</sub></p> +<h2 id="default-implementations">Default implementations</h2> +<p>Trait definitions can also be provided with default implementations of behaviors.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Upload { +</span><span> </span><span style="color:#c82829;">filename</span><span>: String, +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span style="color:#8959a8;">struct </span><span>Photo { +</span><span> </span><span style="color:#c82829;">filename</span><span>: String, +</span><span> </span><span style="color:#c82829;">width</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">height</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Description { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">describe</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;No description available.&quot;</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// All default implementations +</span><span style="color:#8959a8;">impl </span><span>Description </span><span style="color:#8959a8;">for </span><span>Upload {} +</span><span> +</span><span style="color:#999999;">// Default implementations can be overwritten +</span><span style="color:#8959a8;">impl </span><span>Description </span><span style="color:#8959a8;">for </span><span>Photo { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">describe</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;"> x </span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.filename, </span><span style="color:#c82829;">self</span><span>.width, </span><span style="color:#c82829;">self</span><span>.height) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// Default implementations can rely on methods with no defaults +</span><span style="color:#8959a8;">trait </span><span>Size { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">width</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32</span><span>; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">height</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">size</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">width</span><span>() </span><span style="color:#3e999f;">* </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">height</span><span>() +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Size </span><span style="color:#8959a8;">for </span><span>Photo { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">width</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.width +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">height</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.height +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Using default impl of `size()` +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> upload </span><span style="color:#3e999f;">=</span><span> Upload { +</span><span> filename: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;notes.txt&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Upload: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, upload.</span><span style="color:#4271ae;">describe</span><span>()); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> photo </span><span style="color:#3e999f;">=</span><span> Photo { +</span><span> filename: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;stock_crustacean.png&quot;</span><span>), +</span><span> width: </span><span style="color:#f5871f;">100</span><span>, +</span><span> height: </span><span style="color:#f5871f;">150</span><span>, +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Photo: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, photo.</span><span style="color:#4271ae;">describe</span><span>()); +</span><span> println!(</span><span style="color:#718c00;">&quot;Size: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, photo.</span><span style="color:#4271ae;">size</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/trait_default.rs">trait_default.rs</a>)</sub></p> +<h2 id="what-about-derive">What about <em>derive</em>?</h2> +<p>There is a trait-related thing we have used quite extensively and not explained yet, namely the <code>#[derive]</code> attribute. What it does is generate items (in our case a trait implementation) based on the given data definition (here a struct). Below you can find a list of derivable traits from the standard library. Writing derivation rules for user defined traits is also possible, but goes out of the scope of this lesson.</p> +<p>Derivable traits:</p> +<ul> +<li> +<p>Equality traits: <code>Eq</code>, <code>PartialEq</code> and comparison traits: <code>Ord</code> and <code>PartialOrd</code>. The <code>Partial-</code> versions exist because there are types which don't fulfill the reflexivity requirement of equality (<code>NaN != NaN</code>) or do not form a total order (<code> NaN &lt; 0.0 == false</code> and <code>NaN &gt;= 0.0 == false</code>).</p> +</li> +<li> +<p>Data duplication traits: <code>Clone</code> and <code>Copy</code></p> +</li> +<li> +<p><code>Hash</code> - allows using values of that type as keys in a hashmap</p> +</li> +<li> +<p><code>Default</code> - provides a zero-arg constructor function</p> +</li> +<li> +<p><code>Debug</code> - provides a formatting of the value which can be used in debugging context. It should <em>NOT</em> be implemented manually. In general, if it's possible to derive the <code>Debug</code>, there are no reasons against doing it.</p> +</li> +</ul> +<h3 id="when-is-it-possible-to-derive-a-trait">When is it possible to derive a trait?</h3> +<p>When all fields of a struct/variants of an enum implement that trait.</p> +<h3 id="should-all-traits-always-be-derived-if-it-is-possible">Should all traits always be derived if it is possible?</h3> +<p>No. Although it may be tempting to just slap <code>#[derive(Clone, Copy)]</code> everywhere, it would be counter-effective. For example, at some later point you might add a non-Copy field to the struct and your (or, what's worse, someone else's!) code would break. Another example: it makes little sense to use containers as keys in hashmaps or to compare tweets.</p> +<h1 id="generics">Generics</h1> +<p>Suppose we want to find the largest element in a sequence and return it. Very much on purpose, we didn't specify what type these elements would be - ideally, we would love it to work on all types that have a defined notion of a <em>largest</em> element. However, to make things simpler for now, let's focus only on two primitive types: <code>i32</code> and <code>char</code>. Let's try to write the code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest_i32</span><span>(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">i32</span><span>]) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest_char</span><span>(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">char</span><span>]) -&gt; </span><span style="color:#8959a8;">char </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> number_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">34</span><span>, </span><span style="color:#f5871f;">50</span><span>, </span><span style="color:#f5871f;">25</span><span>, </span><span style="color:#f5871f;">100</span><span>, </span><span style="color:#f5871f;">65</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest_i32</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>number_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest number is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> char_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#718c00;">&#39;y&#39;</span><span>, </span><span style="color:#718c00;">&#39;m&#39;</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>, </span><span style="color:#718c00;">&#39;q&#39;</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest_char</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>char_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest char is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/non_generic.rs">non_generic.rs</a>)</sub></p> +<p>Perfect, it works! Now only twenty more types to go...</p> +<p>Fortunately, Rust gives us a way to avoid all this code duplication and generalize the types we're working on.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span></code></pre> +<p>Cleaner already - we merged possibly very many implementations into one. But, when we try to compile this:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0369]: binary operation `&gt;` cannot be applied to type `T` +</span><span> --&gt; src/main.rs:5:17 +</span><span> | +</span><span>5 | if item &gt; largest { +</span><span> | ---- ^ ------- T +</span><span> | | +</span><span> | T +</span><span> | +</span><span>help: consider restricting type parameter `T` +</span><span> | +</span><span>1 | fn largest&lt;T: std::cmp::PartialOrd&gt;(list: &amp;[T]) -&gt; T { +</span><span> | ++++++++++++++++++++++ +</span></code></pre> +<p>Since <code>T</code> can be of absolutely any type now, the compiler cannot be sure that operator <code>&gt;</code> is defined. This aligns with what we wanted, as without comparing elements we don't have a notion of the largest one either. As always, the compiler comes to our aid:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd</span><span>&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span></code></pre> +<p>We call this a <em>trait bound</em>, a way to provide constraints on what kind of types we are talking about in a given context. This implementation almost works now. Let's look at the new error.</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0508]: cannot move out of type `[T]`, a non-copy slice +</span><span> --&gt; src/main.rs:2:23 +</span><span> | +</span><span>2 | let mut largest = list[0]; +</span><span> | ^^^^^^^ +</span><span> | | +</span><span> | cannot move out of here +</span><span> | move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait +</span><span> | help: consider borrowing here: `&amp;list[0]` +</span><span> +</span><span>error[E0507]: cannot move out of a shared reference +</span><span> --&gt; src/main.rs:4:18 +</span><span> | +</span><span>4 | for &amp;item in list { +</span><span> | ----- ^^^^ +</span><span> | || +</span><span> | |data moved here +</span><span> | |move occurs because `item` has type `T`, which does not implement the `Copy` trait +</span><span> | help: consider removing the `&amp;`: `item` +</span></code></pre> +<p>Our function attempts to take ownership, but, again, the compiler doesn't know whether <code>T</code> can just be trivially copied. Rust allows us to combine multiple trait bounds together:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd </span><span style="color:#3e999f;">+ </span><span style="color:#c99e00;">Copy</span><span>&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> number_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">34</span><span>, </span><span style="color:#f5871f;">50</span><span>, </span><span style="color:#f5871f;">25</span><span>, </span><span style="color:#f5871f;">100</span><span>, </span><span style="color:#f5871f;">65</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>number_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest number is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> char_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#718c00;">&#39;y&#39;</span><span>, </span><span style="color:#718c00;">&#39;m&#39;</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>, </span><span style="color:#718c00;">&#39;q&#39;</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>char_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest char is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/generic_largest.rs">generic_largest.rs</a>)</sub></p> +<h2 id="a-powerful-tool">A powerful tool</h2> +<p>There's a lot more that we can do with generics:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Debug; +</span><span> +</span><span style="color:#999999;">// generic enums +</span><span style="color:#8959a8;">enum </span><span>OurOption&lt;T&gt; { +</span><span> </span><span style="color:#c99e00;">Some</span><span>(T), +</span><span> </span><span style="color:#c99e00;">None</span><span>, +</span><span>} +</span><span> +</span><span style="color:#999999;">// generic structs +</span><span style="color:#8959a8;">struct </span><span>Tuple2&lt;T, U&gt; { +</span><span> </span><span style="color:#c82829;">x</span><span>: T, +</span><span> </span><span style="color:#c82829;">y</span><span>: U, +</span><span>} +</span><span> +</span><span style="color:#999999;">// generic implementation +</span><span style="color:#8959a8;">impl</span><span>&lt;T, U&gt; Tuple2&lt;T, U&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: T, </span><span style="color:#f5871f;">y</span><span>: U) -&gt; </span><span style="color:#8959a8;">Self </span><span>{ +</span><span> </span><span style="color:#8959a8;">Self </span><span>{ x, y } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Pair&lt;T&gt; { +</span><span> </span><span style="color:#c82829;">x</span><span>: T, +</span><span> </span><span style="color:#c82829;">y</span><span>: T, +</span><span>} +</span><span> +</span><span style="color:#999999;">// conditional implementation +</span><span style="color:#8959a8;">impl</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd </span><span style="color:#3e999f;">+ </span><span style="color:#c99e00;">Copy</span><span>&gt; Pair&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; T { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.x </span><span style="color:#3e999f;">&gt; </span><span style="color:#c82829;">self</span><span>.y { +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.y +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// alternative syntax +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; Pair&lt;T&gt; +</span><span style="color:#8959a8;">where +</span><span> T: PartialOrd + Copy, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">smallest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; T { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.x </span><span style="color:#3e999f;">&lt; </span><span style="color:#c82829;">self</span><span>.y { +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.y +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// Here information about the concrete underlying type is erased +</span><span style="color:#999999;">// We can only either format or clone the result +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">cloning_machine</span><span>(</span><span style="color:#f5871f;">item</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>(</span><span style="color:#f5871f;">impl Clone</span><span> + </span><span style="color:#f5871f;">Debug</span><span>)) -&gt; impl Clone </span><span style="color:#3e999f;">+</span><span> Debug { +</span><span> item.</span><span style="color:#4271ae;">clone</span><span>() +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> _opt </span><span style="color:#3e999f;">= </span><span>OurOption::Some(</span><span style="color:#f5871f;">10</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _p1 </span><span style="color:#3e999f;">=</span><span> Tuple2 { x: </span><span style="color:#f5871f;">5</span><span>, y: </span><span style="color:#f5871f;">10 </span><span>}; +</span><span> </span><span style="color:#8959a8;">let</span><span> _p2 </span><span style="color:#3e999f;">= </span><span>Tuple2::new(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2.5</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> arr </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> </span><span style="color:#8959a8;">let</span><span> arr2 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">cloning_machine</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>arr); +</span><span> </span><span style="color:#999999;">// arr2[0]; // won&#39;t compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, arr2) +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/generics.rs">generics.rs</a>)</sub></p> +<p>A bit more involved example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::fmt::{Display, Formatter}; +</span><span> +</span><span style="color:#8959a8;">trait </span><span>DefaultishablyPrintable&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">defaultish_print</span><span>() +</span><span> </span><span style="color:#8959a8;">where +</span><span> T: Display + Default, +</span><span> { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, T::default()) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Foo; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Bar; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>Bar { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> f.</span><span style="color:#4271ae;">write_str</span><span>(</span><span style="color:#718c00;">&quot;this is a bar&quot;</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Default </span><span style="color:#8959a8;">for </span><span>Bar { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">default</span><span>() -&gt; </span><span style="color:#8959a8;">Self </span><span>{ +</span><span> Bar </span><span style="color:#999999;">// well, we have no other choice +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>DefaultishablyPrintable&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Foo {} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>DefaultishablyPrintable&lt;Bar&gt; </span><span style="color:#8959a8;">for </span><span>Foo {} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#3e999f;">&lt;</span><span>Foo </span><span style="color:#3e999f;">as </span><span>DefaultishablyPrintable&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;</span><span style="color:#3e999f;">&gt;</span><span>::defaultish_print(); +</span><span> &lt;Foo </span><span style="color:#3e999f;">as </span><span>DefaultishablyPrintable&lt;Bar&gt;&gt;::defaultish_print(); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/generics_fun.rs">generics_fun.rs</a>)</sub></p> +<h2 id="static-vs-dynamic-dispatch">Static vs dynamic dispatch</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>Speak { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str</span><span>; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Dog; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Speak </span><span style="color:#8959a8;">for </span><span>Dog { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;Hau hau&quot; </span><span style="color:#999999;">// it&#39;s a Polish dog! +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Human; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Speak </span><span style="color:#8959a8;">for </span><span>Human { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;Hello world&quot; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// It works like templates in C++ +</span><span style="color:#999999;">// A different function will be generated for each T during compilation +</span><span style="color:#999999;">// This process is called &quot;monomorphization&quot; +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">static_dispatch</span><span>&lt;T: Speak&gt;(</span><span style="color:#f5871f;">speaking</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>T) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, speaking.</span><span style="color:#4271ae;">speak</span><span>()); +</span><span>} +</span><span> +</span><span style="color:#999999;">// Only one copy of that function will exist in the compiled binary +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#f5871f;">speaking</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>dyn Speak) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, speaking.</span><span style="color:#4271ae;">speak</span><span>()); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> dog </span><span style="color:#3e999f;">=</span><span> Dog; +</span><span> </span><span style="color:#8959a8;">let</span><span> human </span><span style="color:#3e999f;">=</span><span> Human; +</span><span> +</span><span> </span><span style="color:#4271ae;">static_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>dog); +</span><span> </span><span style="color:#4271ae;">static_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>human); +</span><span> +</span><span> </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>dog); +</span><span> </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>human); +</span><span> +</span><span> </span><span style="color:#999999;">// The observable behavior is identical +</span><span> </span><span style="color:#999999;">// Static dispatch in general is a bit faster, +</span><span> </span><span style="color:#999999;">// because there is no need to perform a &quot;vtable lookup&quot;. +</span><span> </span><span style="color:#999999;">// But it can also result in bigger binary sizes. +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/static_dynamic_dispatch.rs">static_dynamic_dispatch.rs</a>)</sub></p> +<h1 id="lifetimes">Lifetimes</h1> +<p>Going back to the lesson about ownership, if we try to compile the following code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> r; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; +</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); +</span><span>} +</span></code></pre> +<p>we should expect to get an error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0597]: `x` does not live long enough +</span><span> --&gt; src/main.rs:7:17 +</span><span> | +</span><span>7 | r = &amp;x; +</span><span> | ^^ borrowed value does not live long enough +</span><span>8 | } +</span><span> | - `x` dropped here while still borrowed +</span><span>9 | +</span><span>10 | println!(&quot;r: {}&quot;, r); +</span><span> | - borrow later used here +</span></code></pre> +<p>Courtesy of the borrow checker, we didn't end up with a dangling reference. But what exactly is happening behind the scenes? Rust introduces a concept of annotated lifetimes, where the lifetime of each value is being marked and tracked by the checker. Let's look at some examples:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> r; </span><span style="color:#999999;">// ---------+-- &#39;a +</span><span> </span><span style="color:#999999;">// | +</span><span> { </span><span style="color:#999999;">// | +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// -+-- &#39;b | +</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; </span><span style="color:#999999;">// | | +</span><span> } </span><span style="color:#999999;">// -+ | +</span><span> </span><span style="color:#999999;">// | +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); </span><span style="color:#999999;">// | +</span><span>} </span><span style="color:#999999;">// ---------+ +</span></code></pre> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// ----------+-- &#39;b +</span><span> </span><span style="color:#999999;">// | +</span><span> </span><span style="color:#8959a8;">let</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; </span><span style="color:#999999;">// --+-- &#39;a | +</span><span> </span><span style="color:#999999;">// | | +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); </span><span style="color:#999999;">// | | +</span><span> </span><span style="color:#999999;">// --+ | +</span><span>} </span><span style="color:#999999;">// ----------+ +</span></code></pre> +<h2 id="annotations">Annotations</h2> +<p>Let's consider the following code finding the longer out of two strings:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>, </span><span style="color:#f5871f;">y</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> y.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> y +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> string1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;abcd&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> string2 </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;xyz&quot;</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">longest</span><span>(string1.</span><span style="color:#4271ae;">as_str</span><span>(), string2); +</span><span> println!(</span><span style="color:#718c00;">&quot;The longest string is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span></code></pre> +<p>If we try to compile this, we will get an error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0106]: missing lifetime specifier +</span><span> --&gt; src/main.rs:9:33 +</span><span> | +</span><span>9 | fn longest(x: &amp;str, y: &amp;str) -&gt; &amp;str { +</span><span> | ---- ---- ^ expected named lifetime parameter +</span><span> | +</span><span> = help: this function&#39;s return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +</span><span>help: consider introducing a named lifetime parameter +</span><span> | +</span><span>9 | fn longest&lt;&#39;a&gt;(x: &amp;&#39;a str, y: &amp;&#39;a str) -&gt; &amp;&#39;a str { +</span><span> | ++++ ++ ++ ++ +</span></code></pre> +<p>This is because Rust doesn't know which of the two provided strings (<code>x</code> or <code>y</code>) will be returned from the function. And because they potentially have different lifetimes, the lifetime of what we are returning remains unclear to the compiler - it needs our help.</p> +<p>Rust provides syntax for specifying lifetimes. The lifetime parameter name from the example (<code>a</code>) doesn't have any concrete meaning - it's just an arbitrary name for this one lifetime.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">i32 </span><span style="color:#999999;">// a reference +</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a i32 </span><span style="color:#999999;">// a reference with an explicit lifetime +</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a mut i32 </span><span style="color:#999999;">// a mutable reference with an explicit lifetime +</span></code></pre> +<p>So, knowing this, let's address the compiler's demands.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>, </span><span style="color:#f5871f;">y</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> y.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> y +</span><span> } +</span><span>} +</span></code></pre> +<p>When working with lifetimes, our work will usually revolve around specifying relationships between lifetimes of different values so that the compiler can successfully reason about the program's safety. In the context of the example above, this signature means that both of the function's arguments and its output will live at least as long as lifetime <code>'a</code>. In practice, this means that the output's lifetime will be equal to the smaller of the two inputs' lifetimes.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">first</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>, </span><span style="color:#f5871f;">second</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> first.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> second.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> first +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> second +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> string1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;long string is long&quot;</span><span>); +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> string2 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;xyz&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">longest</span><span>(string1.</span><span style="color:#4271ae;">as_str</span><span>(), string2.</span><span style="color:#4271ae;">as_str</span><span>()); +</span><span> println!(</span><span style="color:#718c00;">&quot;The longest string is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// This doesn&#39;t compile - incorrect lifetimes +</span><span> </span><span style="color:#999999;">// +</span><span> </span><span style="color:#999999;">// let string1 = String::from(&quot;long string is long&quot;); +</span><span> </span><span style="color:#999999;">// let result; +</span><span> </span><span style="color:#999999;">// { +</span><span> </span><span style="color:#999999;">// let string2 = String::from(&quot;xyz&quot;); +</span><span> </span><span style="color:#999999;">// result = longest(string1.as_str(), string2.as_str()); +</span><span> </span><span style="color:#999999;">// } +</span><span> </span><span style="color:#999999;">// println!(&quot;The longest string is {}&quot;, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/lifetimes_basic.rs">lifetimes_basic.rs</a>)</sub></p> +<p>Trying to compile the second variant displeases the compiler (just like we hoped).</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0597]: `string2` does not live long enough +</span><span> --&gt; src/main.rs:6:44 +</span><span> | +</span><span>6 | result = longest(string1.as_str(), string2.as_str()); +</span><span> | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough +</span><span>7 | } +</span><span> | - `string2` dropped here while still borrowed +</span><span>8 | println!(&quot;The longest string is {}&quot;, result); +</span><span> | ------ borrow later used here +</span></code></pre> +<h2 id="lifetime-elision">Lifetime elision</h2> +<p>We now know how to explicitly write lifetime parameters, but you might recall that we don't always have to that. Indeed, Rust will first try to figure out the lifetimes itself, applying a set of predefined rules. We call this <em>lifetime elision</em>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span><span> </span><span style="color:#8959a8;">if</span><span> seq.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&lt; </span><span style="color:#f5871f;">2 </span><span>{ +</span><span> seq +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>seq[</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">2</span><span>] +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> seq </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>]; +</span><span> +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;First two elements of the sequence: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, +</span><span> </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>seq[</span><span style="color:#3e999f;">..</span><span>]) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/05-types-reasoning/lifetimes_elision.rs">lifetimes_elision.rs</a>)</sub></p> +<p>The above works, even though we didn't specify any lifetime parameters at all. The reason lies in the rules we mentioned, which are as follows (where input lifetimes are lifetimes on parameters and output lifetimes are lifetimes on return values):</p> +<ul> +<li> +<p>Each parameter that is a reference gets its own lifetime parameter.</p> +</li> +<li> +<p>If there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters.</p> +</li> +<li> +<p>If there are multiple input lifetime parameters, but one of them is <code>&amp;self</code> or <code>&amp;mut self</code>, the lifetime of <code>self</code> is assigned to all output lifetime parameters.</p> +</li> +</ul> +<p>Let's try to understand how the compiler inferred the lifetimes of our <code>first_two</code> functions. We start with the following signature:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>Then, we apply the first rule:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> [</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>Next, we check the second rule. It applies here as well.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> [</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>With that, we arrive at a state where all lifetimes are specified.</p> +<h2 id="static-lifetime">Static lifetime</h2> +<p>There exists one special lifetime called <code>'static</code>, which means that a reference can live for the entire duration of the program. All string literals are annotated with this lifetime as they are stored directly in the program's binary. Full type annotation of a string literal in Rust is therefore as follows:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;I have a static lifetime.&quot;</span><span>; +</span></code></pre> +<h1 id="obligatory-reading">Obligatory reading</h1> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch10-00-generics.html">The Book, chapter 10</a></p> +</li> +<li> +<p><a href="https://oswalt.dev/2021/06/polymorphism-in-rust/">Polymorphism in Rust</a></p> +</li> +</ul> + + + + + Feedback #1 + 2022-10-31T00:00:00+00:00 + 2022-10-31T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/04-feedback-1/ + + <h2 id="feedback">Feedback</h2> +<h3 id="unwrapping">Unwrapping</h3> +<p>Instead of this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.favorite_color.</span><span style="color:#4271ae;">is_some</span><span>() { +</span><span> </span><span style="color:#c82829;">self</span><span>.favorite_color.</span><span style="color:#4271ae;">as_mut</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>().</span><span style="color:#4271ae;">lighten</span><span>(); +</span><span>} +</span></code></pre> +<p>do this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#8959a8;">ref mut</span><span> color) </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.favorite_color { +</span><span> color.</span><span style="color:#4271ae;">lighten</span><span>(); +</span><span>} +</span></code></pre> +<p>or</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(color) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.favorite_color { +</span><span> color.</span><span style="color:#4271ae;">lighten</span><span>(); +</span><span>} +</span></code></pre> +<p>(unwrapping is a code smell)</p> +<h3 id="spot-the-overflow">Spot the overflow</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Rgb(r, g, b) </span><span style="color:#3e999f;">=&gt; *</span><span>b </span><span style="color:#3e999f;">&gt; </span><span>(</span><span style="color:#3e999f;">*</span><span>r </span><span style="color:#3e999f;">+ *</span><span>g) </span><span style="color:#3e999f;">/ </span><span style="color:#f5871f;">2</span><span>, +</span></code></pre> +<h3 id="1-3">1/3</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Rgb(r, g, b) </span><span style="color:#3e999f;">=&gt; </span><span>(</span><span style="color:#3e999f;">*</span><span>b </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>) </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">3 </span><span style="color:#3e999f;">&gt; </span><span>(</span><span style="color:#3e999f;">*</span><span>r </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>) </span><span style="color:#3e999f;">+ </span><span>(</span><span style="color:#3e999f;">*</span><span>g </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>) </span><span style="color:#3e999f;">+ </span><span>(</span><span style="color:#3e999f;">*</span><span>b </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>), +</span></code></pre> +<p>No need to cast to u16. If b accounts for 1/3 of the sum, it's enough to check that it's bigger than both r and g.</p> +<h3 id="format">Format</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Named(</span><span style="color:#8959a8;">ref mut</span><span> name) </span><span style="color:#3e999f;">=&gt; *</span><span>name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;light &quot;</span><span>.</span><span style="color:#4271ae;">to_string</span><span>() </span><span style="color:#3e999f;">+</span><span> name, +</span></code></pre> +<p>There's a <code>format!</code> macro for this.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Named(</span><span style="color:#8959a8;">ref mut</span><span> name) </span><span style="color:#3e999f;">=&gt; *</span><span>name </span><span style="color:#3e999f;">= </span><span>format!(</span><span style="color:#718c00;">&quot;light </span><span style="color:#666969;">{name}</span><span style="color:#718c00;">&quot;</span><span>), +</span></code></pre> +<h3 id="from-vs-into-vs-as">From vs Into vs as</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span>&lt;</span><span style="color:#8959a8;">u8 </span><span style="color:#3e999f;">as </span><span style="color:#c99e00;">Into</span><span>&lt;</span><span style="color:#8959a8;">u32</span><span>&gt;&gt;::into(</span><span style="color:#3e999f;">*</span><span>c) </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p>This could be written as</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span>(</span><span style="color:#3e999f;">*</span><span>c).</span><span style="color:#4271ae;">into</span><span>() </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p>or even simpler (note the omission of the type annotation):</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1 </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">u32</span><span>::from(</span><span style="color:#3e999f;">*</span><span>c) </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p>However in most cases of numeric conversion you can just use <code>as</code>:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1 </span><span style="color:#3e999f;">= *</span><span>c </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p><a href="https://doc.rust-lang.org/std/convert/trait.Into.html">Into trait docs</a></p> +<h3 id="saturating-addition">Saturating addition</h3> +<p>There's a <code>saturating_add</code> method on <code>u8</code> which does exactly what we wanted. +But it was fun watching you struggle with it :)</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">lighten</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#c82829;">self </span><span>{ +</span><span> Color::Named(name) </span><span style="color:#3e999f;">=&gt; *</span><span>name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;light &quot;</span><span>.</span><span style="color:#4271ae;">to_string</span><span>() </span><span style="color:#3e999f;">+</span><span> name, +</span><span> Color::Rgb(r, g, b) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>r </span><span style="color:#3e999f;">=</span><span> r.</span><span style="color:#4271ae;">saturating_add</span><span>(</span><span style="color:#f5871f;">10</span><span>); +</span><span> </span><span style="color:#3e999f;">*</span><span>g </span><span style="color:#3e999f;">=</span><span> g.</span><span style="color:#4271ae;">saturating_add</span><span>(</span><span style="color:#f5871f;">10</span><span>); +</span><span> </span><span style="color:#3e999f;">*</span><span>b </span><span style="color:#3e999f;">=</span><span> b.</span><span style="color:#4271ae;">saturating_add</span><span>(</span><span style="color:#f5871f;">10</span><span>); +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="exchange">Exchange</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">exchange_items</span><span>(</span><span style="color:#f5871f;">robot1</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> Robot, </span><span style="color:#f5871f;">robot2</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> Robot) { +</span><span> mem::swap(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> robot1.held_item, </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> robot2.held_item); +</span><span>} +</span></code></pre> +<p>Swap is the preferred way to exchange the contents of two variables.</p> +<h3 id="regex-nope">Regex? Nope</h3> +<p>There's no need to use a regex here. String has a <code>contains</code> method.</p> +<p>If you <strong>really</strong> want to use a regex, +you can use the <code>lazy_static</code> crate to avoid recompiling the regex every time you call the function.</p> + + + + + Feedback #1 + 2022-10-31T00:00:00+00:00 + 2022-10-31T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/04-feedback-1/ + + <h2 id="feedback">Feedback</h2> +<h3 id="unwrapping">Unwrapping</h3> +<p>Instead of this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.favorite_color.</span><span style="color:#4271ae;">is_some</span><span>() { +</span><span> </span><span style="color:#c82829;">self</span><span>.favorite_color.</span><span style="color:#4271ae;">as_mut</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>().</span><span style="color:#4271ae;">lighten</span><span>(); +</span><span>} +</span></code></pre> +<p>do this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#8959a8;">ref mut</span><span> color) </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.favorite_color { +</span><span> color.</span><span style="color:#4271ae;">lighten</span><span>(); +</span><span>} +</span></code></pre> +<p>or</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(color) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.favorite_color { +</span><span> color.</span><span style="color:#4271ae;">lighten</span><span>(); +</span><span>} +</span></code></pre> +<p>(unwrapping is a code smell)</p> +<h3 id="spot-the-overflow">Spot the overflow</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Rgb(r, g, b) </span><span style="color:#3e999f;">=&gt; *</span><span>b </span><span style="color:#3e999f;">&gt; </span><span>(</span><span style="color:#3e999f;">*</span><span>r </span><span style="color:#3e999f;">+ *</span><span>g) </span><span style="color:#3e999f;">/ </span><span style="color:#f5871f;">2</span><span>, +</span></code></pre> +<h3 id="1-3">1/3</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Rgb(r, g, b) </span><span style="color:#3e999f;">=&gt; </span><span>(</span><span style="color:#3e999f;">*</span><span>b </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>) </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">3 </span><span style="color:#3e999f;">&gt; </span><span>(</span><span style="color:#3e999f;">*</span><span>r </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>) </span><span style="color:#3e999f;">+ </span><span>(</span><span style="color:#3e999f;">*</span><span>g </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>) </span><span style="color:#3e999f;">+ </span><span>(</span><span style="color:#3e999f;">*</span><span>b </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u16</span><span>), +</span></code></pre> +<p>No need to cast to u16. If b accounts for 1/3 of the sum, it's enough to check that it's bigger than both r and g.</p> +<h3 id="format">Format</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Named(</span><span style="color:#8959a8;">ref mut</span><span> name) </span><span style="color:#3e999f;">=&gt; *</span><span>name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;light &quot;</span><span>.</span><span style="color:#4271ae;">to_string</span><span>() </span><span style="color:#3e999f;">+</span><span> name, +</span></code></pre> +<p>There's a <code>format!</code> macro for this.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Color::Named(</span><span style="color:#8959a8;">ref mut</span><span> name) </span><span style="color:#3e999f;">=&gt; *</span><span>name </span><span style="color:#3e999f;">= </span><span>format!(</span><span style="color:#718c00;">&quot;light </span><span style="color:#666969;">{name}</span><span style="color:#718c00;">&quot;</span><span>), +</span></code></pre> +<h3 id="from-vs-into-vs-as">From vs Into vs as</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span>&lt;</span><span style="color:#8959a8;">u8 </span><span style="color:#3e999f;">as </span><span style="color:#c99e00;">Into</span><span>&lt;</span><span style="color:#8959a8;">u32</span><span>&gt;&gt;::into(</span><span style="color:#3e999f;">*</span><span>c) </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p>This could be written as</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span>(</span><span style="color:#3e999f;">*</span><span>c).</span><span style="color:#4271ae;">into</span><span>() </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p>or even simpler (note the omission of the type annotation):</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1 </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">u32</span><span>::from(</span><span style="color:#3e999f;">*</span><span>c) </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p>However in most cases of numeric conversion you can just use <code>as</code>:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> tmp1 </span><span style="color:#3e999f;">= *</span><span>c </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>; +</span></code></pre> +<p><a href="https://doc.rust-lang.org/std/convert/trait.Into.html">Into trait docs</a></p> +<h3 id="saturating-addition">Saturating addition</h3> +<p>There's a <code>saturating_add</code> method on <code>u8</code> which does exactly what we wanted. +But it was fun watching you struggle with it :)</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">lighten</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#c82829;">self </span><span>{ +</span><span> Color::Named(name) </span><span style="color:#3e999f;">=&gt; *</span><span>name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;light &quot;</span><span>.</span><span style="color:#4271ae;">to_string</span><span>() </span><span style="color:#3e999f;">+</span><span> name, +</span><span> Color::Rgb(r, g, b) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>r </span><span style="color:#3e999f;">=</span><span> r.</span><span style="color:#4271ae;">saturating_add</span><span>(</span><span style="color:#f5871f;">10</span><span>); +</span><span> </span><span style="color:#3e999f;">*</span><span>g </span><span style="color:#3e999f;">=</span><span> g.</span><span style="color:#4271ae;">saturating_add</span><span>(</span><span style="color:#f5871f;">10</span><span>); +</span><span> </span><span style="color:#3e999f;">*</span><span>b </span><span style="color:#3e999f;">=</span><span> b.</span><span style="color:#4271ae;">saturating_add</span><span>(</span><span style="color:#f5871f;">10</span><span>); +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="exchange">Exchange</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">exchange_items</span><span>(</span><span style="color:#f5871f;">robot1</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> Robot, </span><span style="color:#f5871f;">robot2</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> Robot) { +</span><span> mem::swap(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> robot1.held_item, </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> robot2.held_item); +</span><span>} +</span></code></pre> +<p>Swap is the preferred way to exchange the contents of two variables.</p> +<h3 id="regex-nope">Regex? Nope</h3> +<p>There's no need to use a regex here. String has a <code>contains</code> method.</p> +<p>If you <strong>really</strong> want to use a regex, +you can use the <code>lazy_static</code> crate to avoid recompiling the regex every time you call the function.</p> + + + + + Data Types + 2022-10-24T00:00:00+00:00 + 2022-10-24T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/ + + <h2 id="aggregating-data">Aggregating data</h2> +<p>Below is a compact overview of Rust's structs</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#[</span><span style="color:#c82829;">derive</span><span>(Clone, Copy, Debug, Eq, PartialEq)] +</span><span style="color:#8959a8;">struct </span><span>Position(</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#8959a8;">i32</span><span>); </span><span style="color:#999999;">// tuple struct +</span><span> +</span><span style="color:#999999;">// Could Hero derive the Copy trait? +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Clone, Debug, Eq, PartialEq)] +</span><span style="color:#8959a8;">struct </span><span>Hero { +</span><span> </span><span style="color:#c82829;">name</span><span>: String, +</span><span> </span><span style="color:#c82829;">level</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">experience</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">position</span><span>: Position, +</span><span>} +</span><span> +</span><span style="color:#999999;">// we can add methods to structs using the &#39;impl&#39; keyword +</span><span style="color:#8959a8;">impl </span><span>Hero { +</span><span> </span><span style="color:#999999;">// static method (in Rust nomenclature: &quot;associated function&quot;) +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">name</span><span>: String) -&gt; Hero { +</span><span> Hero { +</span><span> name, +</span><span> level: </span><span style="color:#f5871f;">1</span><span>, +</span><span> experience: </span><span style="color:#f5871f;">0</span><span>, +</span><span> position: Position(</span><span style="color:#f5871f;">0</span><span>, </span><span style="color:#f5871f;">0</span><span>), +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// multiple impl blocks are possible for one struct +</span><span style="color:#8959a8;">impl </span><span>Hero { +</span><span> </span><span style="color:#999999;">// instance method, first argument (self) is the calling instance +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">distance</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">pos</span><span>: Position) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#999999;">// shorthand to: `self: &amp;Self` +</span><span> </span><span style="color:#999999;">// field `i` of a tuple or a tuple struct can be accessed through &#39;tuple.i&#39; +</span><span> (pos.</span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">- </span><span style="color:#c82829;">self</span><span>.position.</span><span style="color:#f5871f;">0</span><span>).</span><span style="color:#4271ae;">unsigned_abs</span><span>() </span><span style="color:#3e999f;">+ </span><span>(pos.</span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">- </span><span style="color:#c82829;">self</span><span>.position.</span><span style="color:#f5871f;">1</span><span>).</span><span style="color:#4271ae;">unsigned_abs</span><span>() +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// mutable borrow of self allows to change instance fields +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">level_up</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#999999;">// shorthand to: `self: &amp;mut Self` +</span><span> </span><span style="color:#c82829;">self</span><span>.experience </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#c82829;">self</span><span>.level </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// &#39;self&#39; is not borrowed here and will be moved into the method +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">die</span><span>(</span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#999999;">// shorthand to: `self: Self` +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Here lies </span><span style="color:#666969;">{}</span><span style="color:#718c00;">, a hero who reached level </span><span style="color:#666969;">{}</span><span style="color:#718c00;">. RIP.&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.name, </span><span style="color:#c82829;">self</span><span>.level +</span><span> ); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// Calling associated functions requires scope (`::`) operator. +</span><span> </span><span style="color:#8959a8;">let mut</span><span> hero: Hero </span><span style="color:#3e999f;">= </span><span>Hero::new(</span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Ferris&quot;</span><span>)); +</span><span> hero.</span><span style="color:#4271ae;">level_up</span><span>(); </span><span style="color:#999999;">// &#39;self&#39; is always passed implicitly +</span><span> +</span><span> </span><span style="color:#999999;">// fields other than &#39;name&#39; will be the same as in &#39;hero&#39; +</span><span> </span><span style="color:#8959a8;">let</span><span> steve </span><span style="color:#3e999f;">=</span><span> Hero { +</span><span> name: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Steve The Normal Guy&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">..</span><span>hero +</span><span> }; +</span><span> +</span><span> assert_eq!(hero.level, steve.level); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> twin </span><span style="color:#3e999f;">=</span><span> hero.</span><span style="color:#4271ae;">clone</span><span>(); +</span><span> +</span><span> </span><span style="color:#999999;">// we can compare Hero objects because it derives the PartialEq trait +</span><span> assert_eq!(hero, twin); +</span><span> twin.</span><span style="color:#4271ae;">level_up</span><span>(); +</span><span> assert_ne!(hero, twin); +</span><span> hero.</span><span style="color:#4271ae;">level_up</span><span>(); +</span><span> assert_eq!(hero, twin); +</span><span> +</span><span> </span><span style="color:#999999;">// we can print out a the struct&#39;s debug string with &#39;{:?}&#39; +</span><span> println!(</span><span style="color:#718c00;">&quot;print to stdout: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, hero); +</span><span> +</span><span> hero.</span><span style="color:#4271ae;">die</span><span>(); </span><span style="color:#999999;">// &#39;hero&#39; is not usable after this invocation, see the method&#39;s definiton +</span><span> +</span><span> </span><span style="color:#999999;">// the dbg! macro prints debug strings to stderr along with file and line number +</span><span> </span><span style="color:#999999;">// dbg! takes its arguments by value, so better borrow them not to have them +</span><span> </span><span style="color:#999999;">// moved into dbg! and consumed. +</span><span> dbg!(</span><span style="color:#718c00;">&quot;print to stderr: {}&quot;</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>twin); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> pos </span><span style="color:#3e999f;">=</span><span> Position(</span><span style="color:#f5871f;">42</span><span>, </span><span style="color:#f5871f;">0</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> dist </span><span style="color:#3e999f;">=</span><span> steve.</span><span style="color:#4271ae;">distance</span><span>(pos); </span><span style="color:#999999;">// no clone here as Position derives the Copy trait +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, pos); +</span><span> assert_eq!(dist, </span><span style="color:#f5871f;">42</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/data_types.rs">data_types.rs</a>)</sub></p> +<h2 id="enums">Enums</h2> +<p>It is often the case that we want to define a variable that can only take +a certain set of values and the values are known up front. In C you can an <code>enum</code> for this.</p> +<pre data-lang="c" style="background-color:#ffffff;color:#4d4d4c;" class="language-c "><code class="language-c" data-lang="c"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;stdio.h&gt; +</span><span> +</span><span style="color:#8959a8;">enum </span><span>shirt_size { +</span><span> small, +</span><span> medium, +</span><span> large, +</span><span> xlarge +</span><span>}; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_size</span><span>(</span><span style="color:#8959a8;">enum</span><span> shirt_size </span><span style="color:#f5871f;">size</span><span>) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;my size is &quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">switch </span><span>(size) { +</span><span> </span><span style="color:#8959a8;">case</span><span> small: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;small&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> medium: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;medium&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> large: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;large&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> xlarge: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;xlarge&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">default</span><span>: +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;unknown&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">enum</span><span> shirt_size my_size </span><span style="color:#3e999f;">=</span><span> medium; +</span><span> </span><span style="color:#c82829;">print_size</span><span style="color:#4271ae;">(my_size)</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/enums.c">enums.c</a>)</sub></p> +<p>However, in C enums are just integers. Nothing prevents us from writing</p> +<pre data-lang="c" style="background-color:#ffffff;color:#4d4d4c;" class="language-c "><code class="language-c" data-lang="c"><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">enum</span><span> shirt_size my_size </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">666</span><span>; +</span><span> </span><span style="color:#c82829;">print_size</span><span style="color:#4271ae;">(my_size)</span><span>; +</span><span>} +</span></code></pre> +<p>C++ introduces enum classes which are type-safe. Legacy enums are also somewhat safer than in C (same code as above):</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>&lt;source&gt;:27:31: error: invalid conversion from &#39;int&#39; to &#39;shirt_size&#39; [-fpermissive] +</span><span> 27 | enum shirt_size my_size = 666; +</span><span> | ^~~ +</span><span> | | +</span><span> | int +</span></code></pre> +<p>Some programming languages (especially functional ones) allow programmers to define +enums which carry additional information. Such types are usually called <code>tagged unions</code> +or <code>algebraic data types</code>.</p> +<p>In C++ we can use <code>union</code> with an <code>enum</code> tag to define it:</p> +<pre data-lang="cpp" style="background-color:#ffffff;color:#4d4d4c;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;iostream&gt; +</span><span> +</span><span style="color:#999999;">// Taken from: https://en.cppreference.com/w/cpp/language/union +</span><span> +</span><span style="color:#999999;">// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), +</span><span style="color:#999999;">// and three variant members (c, i, d) +</span><span style="color:#8959a8;">struct </span><span>S +</span><span>{ +</span><span> </span><span style="color:#8959a8;">enum</span><span>{</span><span style="color:#c99e00;">CHAR</span><span>, </span><span style="color:#c99e00;">INT</span><span>, DOUBLE} tag; +</span><span> </span><span style="color:#8959a8;">union +</span><span> { +</span><span> </span><span style="color:#8959a8;">char</span><span> c; +</span><span> </span><span style="color:#8959a8;">int</span><span> i; +</span><span> </span><span style="color:#8959a8;">double</span><span> d; +</span><span> }; +</span><span>}; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_s</span><span>(</span><span style="color:#8959a8;">const</span><span> S</span><span style="color:#3e999f;">&amp; </span><span style="color:#f5871f;">s</span><span>) +</span><span>{ +</span><span> </span><span style="color:#8959a8;">switch</span><span>(s.</span><span style="color:#c82829;">tag</span><span>) +</span><span> { +</span><span> </span><span style="color:#8959a8;">case</span><span> S::</span><span style="color:#c99e00;">CHAR</span><span>: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">c </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> S::</span><span style="color:#c99e00;">INT</span><span>: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">i </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> S::DOUBLE: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">d </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() +</span><span>{ +</span><span> S s </span><span style="color:#3e999f;">= </span><span>{S::</span><span style="color:#c99e00;">CHAR</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>}; +</span><span> </span><span style="color:#c82829;">print_s</span><span style="color:#4271ae;">(s)</span><span>; +</span><span> s.</span><span style="color:#c82829;">tag </span><span style="color:#3e999f;">=</span><span> S::</span><span style="color:#c99e00;">INT</span><span>; +</span><span> s.</span><span style="color:#c82829;">i </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">123</span><span>; +</span><span> </span><span style="color:#c82829;">print_s</span><span style="color:#4271ae;">(s)</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/tagged_union.cpp">tagged_union.cpp</a>)</sub></p> +<p>C++17 introduced a new feature called <code>variant</code> which generalizes this concept. +You can read more about it <a href="https://en.cppreference.com/w/cpp/utility/variant">here</a>.</p> +<p>Java has a more or less analogous feature called <code>sealed classes</code> +since <a href="https://docs.oracle.com/en/java/javase/17/language/sealed-classes-and-interfaces.html.">version 17</a>.</p> +<h2 id="enums-in-rust">Enums in Rust</h2> +<p>Let's see how they are defined in Rust.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span style="color:#8959a8;">enum </span><span>NamedSize { +</span><span> Small, +</span><span> Medium, +</span><span> Large, +</span><span> </span><span style="color:#666969;">XL</span><span>, +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span style="color:#8959a8;">enum </span><span>ShirtSize { +</span><span> Named(NamedSize), +</span><span> Numeric(</span><span style="color:#8959a8;">u32</span><span>), +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Isn&#39;t it strange that some clothes&#39; sizes are adjectives like </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">,&quot;</span><span>, +</span><span> ShirtSize::Named(NamedSize::Small) +</span><span> ); +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;but sometimes they are numbers like </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">?&quot;</span><span>, +</span><span> ShirtSize::Numeric(</span><span style="color:#f5871f;">42</span><span>) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/enums.rs">enums.rs</a>)</sub></p> +<p>In Rust, enums are a core feature of the language. +You may have heard that one of Rust's defining characteristics is +the absence of <a href="https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions">&quot;the billion dollar mistake&quot;</a>. +So what can we do to say that a value is missing if there is no <code>null</code>?</p> +<p>In Rust, we can use the <code>Option</code> type to represent the absence of a value.</p> +<p>Option is defined as:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">enum </span><span>Option&lt;T&gt; { +</span><span> </span><span style="color:#c99e00;">Some</span><span>(T), +</span><span> </span><span style="color:#c99e00;">None</span><span>, +</span><span>} +</span></code></pre> +<p>The <code>&lt;T&gt;</code> part is called the &quot;type parameter&quot; and it causes Option to be generic. +We won't go deeper into this for now.</p> +<p>The fact that variables which could be <code>null</code> in other languages have a different type in Rust is +the solution to the billion dollar mistake!</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> not_null: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> not_null </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">43</span><span>; +</span><span> </span><span style="color:#999999;">// not_null = None; // this won&#39;t compile because it&#39;s a different type! +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> nullable: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">43</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// such construction is rare, but possible +</span><span> </span><span style="color:#8959a8;">let mut</span><span> double_nullable: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> </span><span style="color:#999999;">// assert_ne!(double_nullable, Some(42)); // this won&#39;t even compile because it&#39;s a different type! +</span><span> double_nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> double_nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// None and Some(None) are different! +</span><span> assert_ne!(double_nullable, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// Now recall that division by 0 *panics* +</span><span> </span><span style="color:#999999;">// A panic is an unrecoverable error +</span><span> </span><span style="color:#999999;">// It is not an exception! +</span><span> </span><span style="color:#999999;">// And in Rust there are no exceptions, so there are no try/catch blocks +</span><span> </span><span style="color:#999999;">// Now let&#39;s imagine that we want to divide one number by another +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">divide</span><span>(</span><span style="color:#f5871f;">dividend</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">divisor</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> dividend </span><span style="color:#3e999f;">/</span><span> divisor +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We get the divisor from the user, so it can be 0 +</span><span> </span><span style="color:#999999;">// We want to handle this situation gracefully - we don&#39;t want to crash the program! +</span><span> </span><span style="color:#999999;">// We can do this by using the Option&lt;T&gt; type +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">safe_divide</span><span>(</span><span style="color:#f5871f;">dividend</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">divisor</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">if</span><span> divisor </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#c99e00;">None +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c99e00;">Some</span><span>(dividend </span><span style="color:#3e999f;">/</span><span> divisor) +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Fortunately, such a function is already included in the standard library +</span><span> </span><span style="color:#8959a8;">let</span><span> number: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> </span><span style="color:#999999;">// We need to specify the type explicitly +</span><span> </span><span style="color:#999999;">// because checked_div is implemented for all integer types +</span><span> </span><span style="color:#999999;">// and Rust won&#39;t know which type we want to use +</span><span> assert_eq!(number.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">2</span><span>), </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">21</span><span>)); +</span><span> assert_eq!(number.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">0</span><span>), </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// Now let&#39;s imagine we search for a value in an array. +</span><span> </span><span style="color:#8959a8;">let</span><span> numbers </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>, </span><span style="color:#f5871f;">5</span><span>]; +</span><span> </span><span style="color:#8959a8;">let</span><span> three </span><span style="color:#3e999f;">=</span><span> numbers.</span><span style="color:#4271ae;">iter</span><span>().</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">find</span><span>(|</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">3</span><span>); +</span><span> assert_eq!(three, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> </span><span style="color:#8959a8;">let</span><span> seven </span><span style="color:#3e999f;">=</span><span> numbers.</span><span style="color:#4271ae;">iter</span><span>().</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">find</span><span>(|</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">7</span><span>); +</span><span> assert_eq!(seven, </span><span style="color:#c99e00;">None</span><span>); +</span><span> </span><span style="color:#999999;">// We won&#39;t delve deeper into the details of how iterators work for now, +</span><span> </span><span style="color:#999999;">// but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust +</span><span> +</span><span> </span><span style="color:#999999;">// Usually there are two kinds of methods: +</span><span> </span><span style="color:#999999;">// ones that will panic if the argument is incorrect, +</span><span> </span><span style="color:#999999;">// numbers[8]; // this will panic! +</span><span> </span><span style="color:#999999;">// and `checked` ones that return an Option +</span><span> assert_eq!(numbers.</span><span style="color:#4271ae;">get</span><span>(</span><span style="color:#f5871f;">8</span><span>), </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// We can use `unwrap` to get the value out of an Option +</span><span> </span><span style="color:#999999;">// but we must be absolutely sure that the Option is Some, otherwise we&#39;ll get a panic +</span><span> </span><span style="color:#999999;">// numbers.get(8).unwrap(); // this will panic! +</span><span> assert_eq!(numbers.</span><span style="color:#4271ae;">get</span><span>(</span><span style="color:#f5871f;">8</span><span>).</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">unwrap_or</span><span>(</span><span style="color:#f5871f;">0</span><span>), </span><span style="color:#f5871f;">0</span><span>); </span><span style="color:#999999;">// or we can provide a default value +</span><span> +</span><span> </span><span style="color:#999999;">// Usually instead of unwrapping we use pattern matching, we&#39;ll get to this in a minute +</span><span> </span><span style="color:#999999;">// but first let&#39;s see what else we can do with an option +</span><span> </span><span style="color:#8959a8;">let</span><span> number: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> </span><span style="color:#999999;">// We can use `map` to transform the value inside an Option +</span><span> </span><span style="color:#8959a8;">let</span><span> doubled </span><span style="color:#3e999f;">=</span><span> number.</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>); +</span><span> assert_eq!(doubled, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">84</span><span>)); +</span><span> </span><span style="color:#999999;">// We can use flatten to reduce one level of nesting +</span><span> </span><span style="color:#8959a8;">let</span><span> nested </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> assert_eq!(nested.</span><span style="color:#4271ae;">flatten</span><span>(), </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> </span><span style="color:#999999;">// We can use `and_then` to chain multiple options +</span><span> </span><span style="color:#999999;">// This operation is called `flatmap` in some languages +</span><span> </span><span style="color:#8959a8;">let</span><span> chained </span><span style="color:#3e999f;">=</span><span> number +</span><span> .</span><span style="color:#4271ae;">and_then</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">0</span><span>)) +</span><span> .</span><span style="color:#4271ae;">and_then</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> assert_eq!(chained, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// The last two things we&#39;ll cover here are `take` and `replace` +</span><span> </span><span style="color:#999999;">// They are important when dealing with non-Copy types +</span><span> </span><span style="color:#999999;">// `take` will return the value inside an Option and leave a None in its place +</span><span> </span><span style="color:#8959a8;">let mut</span><span> option: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> </span><span style="color:#999999;">// Again, we need to specify the type +</span><span> </span><span style="color:#999999;">// Even though we want to say that there is no value inside the Option, +</span><span> </span><span style="color:#999999;">// this absent value must have a concrete type! +</span><span> assert_eq!(option.</span><span style="color:#4271ae;">take</span><span>(), </span><span style="color:#c99e00;">None</span><span>); +</span><span> assert_eq!(option, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> y </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">None</span><span>); +</span><span> assert_eq!(y, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// `replace` can be used to swap the value inside an Option +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> old </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> assert_eq!(old, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> old </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#f5871f;">3</span><span>); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> assert_eq!(old, </span><span style="color:#c99e00;">None</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/option.rs">option.rs</a>)</sub></p> +<h2 id="pattern-matching">Pattern matching</h2> +<p>Pattern matching is a powerful feature of Rust and many functional languages, but it's slowly making +its way into imperative languages like Java and Python as well.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// Pattern matching is basically a switch on steroids. +</span><span> </span><span style="color:#8959a8;">let</span><span> number </span><span style="color:#3e999f;">= </span><span>rand::random::&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;(); +</span><span> </span><span style="color:#8959a8;">match</span><span> number </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">7 </span><span>{ +</span><span> </span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is divisible by 7&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is *almost* divisible by 7&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is not divisible by 7&quot;</span><span>), +</span><span> } +</span><span> +</span><span> #[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span> </span><span style="color:#8959a8;">enum </span><span>Color { +</span><span> Pink, +</span><span> Brown, +</span><span> Lime, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> color </span><span style="color:#3e999f;">= </span><span>Color::Lime; +</span><span> </span><span style="color:#8959a8;">match</span><span> color { +</span><span> Color::Pink </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not my favorite color!&quot;</span><span>), </span><span style="color:#999999;">// _ is a wildcard +</span><span> </span><span style="color:#999999;">// Rust will statically check that we covered all cases or included a default case. +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can also use pattern matching to match on multiple values. +</span><span> </span><span style="color:#8959a8;">match </span><span>(color, number </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">7</span><span>) { +</span><span> (Color::Pink, </span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color and number!&quot;</span><span>), +</span><span> (Color::Pink, </span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color!&quot;</span><span>), +</span><span> (</span><span style="color:#3e999f;">_</span><span>, </span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite number!&quot;</span><span>), +</span><span> (</span><span style="color:#3e999f;">_</span><span>, </span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not my favorite color or number!&quot;</span><span>), +</span><span> } +</span><span> </span><span style="color:#999999;">// (This is not special syntax, we&#39;re just pattern matching tuples.) +</span><span> +</span><span> </span><span style="color:#999999;">// But we can also *destructure* the value +</span><span> </span><span style="color:#8959a8;">struct </span><span>Human { +</span><span> </span><span style="color:#c82829;">age</span><span>: </span><span style="color:#8959a8;">u8</span><span>, +</span><span> </span><span style="color:#c82829;">favorite_color</span><span>: Color, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> john </span><span style="color:#3e999f;">=</span><span> Human { +</span><span> age: </span><span style="color:#f5871f;">42</span><span>, +</span><span> favorite_color: Color::Pink, +</span><span> }; +</span><span> +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#3e999f;">&amp;</span><span>john { +</span><span> Human { +</span><span> age: </span><span style="color:#f5871f;">42</span><span>, +</span><span> favorite_color: Color::Pink, +</span><span> } </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Okay, that&#39;s John!&quot;</span><span>), +</span><span> Human { +</span><span> favorite_color: Color::Pink, +</span><span> </span><span style="color:#3e999f;">.. +</span><span> } </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not John, but still his favorite color!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Somebody else?&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Note two things: +</span><span> </span><span style="color:#999999;">// 1. Color is *not* Eq, so we can&#39;t use == to compare it, but pattern matching is fine. +</span><span> </span><span style="color:#999999;">// 2. We *borrowed* the value, so we can use it after the match. +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;John is </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> years old and still kicking!&quot;</span><span>, john.age); +</span><span> +</span><span> </span><span style="color:#999999;">// To save some time, we can use `if let` to match against only one thing +</span><span> </span><span style="color:#999999;">// We could also use `while let ... {}` in the same way +</span><span> </span><span style="color:#8959a8;">if let </span><span>Color::Pink </span><span style="color:#3e999f;">= &amp;</span><span>john.favorite_color { +</span><span> println!(</span><span style="color:#718c00;">&quot;He&#39;s also a man of great taste&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can match ranges... +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">12 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a kid!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">13</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a teenager!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">20</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">29 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a young adult!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">30</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">49 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an adult!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">50</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">69 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is mature!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is old!&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use match and capture the value at the same time. +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">12 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a kid, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">13</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a teenager, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">20</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">29 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a young adult, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">30</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">49 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an adult, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">50</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">69 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is mature, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is old, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use guards to check for multiple conditions. +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">12</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#8959a8;">if</span><span> age </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an *odd* teenager, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#8959a8;">if</span><span> age </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an *even* man, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is normal&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Finally, let&#39;s look at some references now +</span><span> </span><span style="color:#8959a8;">let</span><span> reference: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= &amp;</span><span style="color:#f5871f;">4</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">match</span><span> reference { +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>val </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Value under reference is: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, val), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// `ref` can be used to create a reference when destructuring +</span><span> </span><span style="color:#8959a8;">let</span><span> Human { +</span><span> age, +</span><span> </span><span style="color:#8959a8;">ref</span><span> favorite_color, +</span><span> } </span><span style="color:#3e999f;">=</span><span> john; +</span><span> </span><span style="color:#999999;">// `john` is still valid, because we borrowed using `ref` +</span><span> </span><span style="color:#8959a8;">if let </span><span>Color::Pink </span><span style="color:#3e999f;">= &amp;</span><span>john.favorite_color { +</span><span> println!(</span><span style="color:#718c00;">&quot;John still has his color - </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">!&quot;</span><span>, favorite_color); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> john </span><span style="color:#3e999f;">=</span><span> john; +</span><span> +</span><span> </span><span style="color:#999999;">// `ref mut` borrows mutably +</span><span> </span><span style="color:#8959a8;">let</span><span> Human { +</span><span> age, +</span><span> </span><span style="color:#8959a8;">ref mut</span><span> favorite_color, +</span><span> } </span><span style="color:#3e999f;">=</span><span> john; +</span><span> </span><span style="color:#999999;">// We use `*` to dereference +</span><span> </span><span style="color:#3e999f;">*</span><span>favorite_color </span><span style="color:#3e999f;">= </span><span>Color::Brown; +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Tastes do change with time and John likes </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;"> now.&quot;</span><span>, +</span><span> john.favorite_color +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/pattern_matching.rs">pattern_matching.rs</a>)</sub></p> +<h2 id="result">Result</h2> +<p>We said there are no exceptions in Rust and panics mean errors which cannot be caught. +So how do we handle situations which can fail? That's where the <code>Result</code> type comes in.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fs::File; +</span><span style="color:#8959a8;">use </span><span>std::io; +</span><span style="color:#8959a8;">use </span><span>std::io::Read; +</span><span> +</span><span style="color:#999999;">// Let&#39;s try reading from a file. +</span><span style="color:#999999;">// Obviously this can fail. +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_try</span><span>() -&gt; io::</span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">let</span><span> file </span><span style="color:#3e999f;">= </span><span>File::open(</span><span style="color:#718c00;">&quot;/dev/random&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">match</span><span> file { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#8959a8;">mut</span><span> file) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#999999;">// We got a file! +</span><span> </span><span style="color:#8959a8;">let mut</span><span> buffer </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#f5871f;">128</span><span>]; +</span><span> </span><span style="color:#999999;">// Matching each result quickly become tedious... +</span><span> </span><span style="color:#8959a8;">match</span><span> file.</span><span style="color:#4271ae;">read_exact</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> buffer) { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> gibberish </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from_utf8_lossy(</span><span style="color:#3e999f;">&amp;</span><span>buffer); +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish.</span><span style="color:#4271ae;">to_string</span><span>()) +</span><span> } +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c99e00;">Err</span><span>(error), +</span><span> } +</span><span> } +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#999999;">// This is needed in order to change the type from `io::Result&lt;File&gt;` to `io::Result&lt;()&gt;` +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// The &#39;?&#39; operator allows us to return early in case of an error +</span><span style="color:#999999;">// (it automatically converts the error type) +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">second_try</span><span>(</span><span style="color:#f5871f;">filename</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str</span><span>) -&gt; io::</span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> file </span><span style="color:#3e999f;">= </span><span>File::open(filename)</span><span style="color:#3e999f;">?</span><span>; +</span><span> </span><span style="color:#8959a8;">let mut</span><span> buffer </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#f5871f;">128</span><span>]; +</span><span> file.</span><span style="color:#4271ae;">read_exact</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> buffer)</span><span style="color:#3e999f;">?</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> gibberish </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from_utf8_lossy(</span><span style="color:#3e999f;">&amp;</span><span>buffer); +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish.</span><span style="color:#4271ae;">to_string</span><span>()) +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> filenames </span><span style="color:#3e999f;">= </span><span>[ +</span><span> </span><span style="color:#718c00;">&quot;/dev/random&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/null&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/cpu&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/fuse&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;there_certainly_is_no_such_file&quot;</span><span>, +</span><span> ]; +</span><span> </span><span style="color:#8959a8;">for</span><span> filename </span><span style="color:#3e999f;">in</span><span> filenames { +</span><span> println!(</span><span style="color:#718c00;">&quot;Trying to read from &#39;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&#39;&quot;</span><span>, filename); +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#4271ae;">second_try</span><span>(filename) { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, gibberish), +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Error: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, error), +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/03-data-types/result.rs">result.rs</a>)</sub></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li>The Book, chapters <a href="https://doc.rust-lang.org/book/ch05-00-structs.html">5</a>, +<a href="https://doc.rust-lang.org/stable/book/ch06-00-enums.html">6</a>, +<a href="https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html">8</a> +and <a href="https://doc.rust-lang.org/stable/book/ch09-00-error-handling.html">9</a></li> +<li><a href="https://doc.rust-lang.org/std/option/">Option docs</a></li> +<li><a href="https://doc.rust-lang.org/std/result/">Result docs</a></li> +</ul> +<h2 id="assignment-1-graded">Assignment #1 (graded)</h2> +<p>(TBA)</p> + + + + + Ownership Model + 2022-10-17T00:00:00+00:00 + 2022-10-17T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/02-ownership/ + + <h2 id="why-all-the-fuss">Why all the fuss?</h2> +<p>Even if you've never seen Rust code before, chances are you still heard the term <em>borrow checker</em> or something about Rust's ownership. Indeed, Rust's ownership model lies at the very core of its uniqueness. But to fully understand it and appreciate it, let's first take a look at how memory management is handled in most popular languages.</p> +<ul> +<li> +<p><strong>Garbage Collection</strong> - in many high-level programming languages, like Java, Haskell or Python, memory management is done fully by the language, relieving the programmer from this burden. This prevents memory leaks and memory related errors (like <em>use after free</em>), but does come at a cost - there is a runtime overhead, both memory and performance wise, caused by the constantly running garbage collection algorithms and the programmer usually has very little control over when the garbage collection takes place.</p> +</li> +<li> +<p><strong>Mind your own memory</strong> - in low-level languages and specific ones like C++, performance comes first so we cannot really afford to run expansive bookkeeping and cleaning algorithms. Most of these languages compile directly to machine code and have no language-specific runtime environment. That means that the only place where memory management can happen is in the produced code. While compilers insert these construction and destruction calls for stack allocated memory, it generally requires a lot of discipline from the programmer to adhere to good practices and patterns to avoid as many memory related issues as possible and one such bug can be quite deadly to the program and a nightmare to find and fix. These languages basically live by the <em>&quot;your memory, your problem&quot;</em> mantra.</p> +</li> +</ul> +<p>And then we have Rust. Rust is a systems programming language and in many ways it's akin to C++ - it's basically low-level with many high-level additions. But unlike C++, it doesn't exactly fall into either of the categories described above, though it's way closer to the second one. It performs no additional management at runtime, but instead imposes a set of rules on the code, making it easier to reason about and thus check for its safety and correctness at compile time - these rules make up Rust's <strong>ownership model</strong>.</p> +<p>In a way, programming in Rust is like pair-programming with a patient and very experienced partner. Rust's compiler will make sure you follow all the good patterns and practices (by having them ingrained in the language itself) and very often even tell you how to fix the issues it finds.</p> +<p><em><strong>Disclaimer:</strong> when delving deeper into Rust below we will make heavy use of concepts like scopes, moving data, stack and heap, which should have been introduced as part of the JNP1 C++ course. If you need a refresher of any of these, it's best to do so now, before reading further.</em></p> +<h2 id="start-with-the-basics-ownership">Start with the basics - ownership</h2> +<p>In the paragraph above we mentioned a set of rules that comprise Rust's ownership model. <a href="https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ownership-rules">The book</a> starts off with the following three as its very foundation:</p> +<ol> +<li> +<p>Each value in Rust is tied to a specific variable - we call that variable its <strong>owner</strong>.</p> +</li> +<li> +<p>There can only be one owner at a time.</p> +</li> +<li> +<p>When the owner goes out of scope, the value will be destroyed (or in Rust terms - <em>dropped</em>).</p> +</li> +</ol> +<p>The third point might make you think about C++ and its automatic storage duration. We will later see that, while very similar at first, Rust expands on these mechanics quite a bit. The following code illustrates the basic version of this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> a: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// allocation on the stack, &#39;a&#39; becomes an owner +</span><span> +</span><span> </span><span style="color:#999999;">// do some stuff with &#39;a&#39; +</span><span> +</span><span>} </span><span style="color:#999999;">// &#39;a&#39;, the owner, goes out of scope and the value is dropped +</span></code></pre> +<p>So far, so good. Variables are pushed onto the stack when they enter the scope and destroyed during stack unwinding that happens upon leaving their scope. However, allocating and deallocating simple integers doesn't impress anybody. Let's try something more complex:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// &#39;s&#39; is allocated on the stack, while its contents (&quot;a string&quot;) +</span><span> </span><span style="color:#999999;">// are allocated on the heap. &#39;s&#39; is the owner of this String object. +</span><span> +</span><span> </span><span style="color:#999999;">// do some stuff with &#39;s&#39; +</span><span> +</span><span>} </span><span style="color:#999999;">// &#39;s&#39;, the owner, goes out of scope and the String is dropped, its heap allocated memory freed +</span></code></pre> +<p>If you recall the RAII (Resource Acquisition Is Initialization) pattern from C++, the above is basically the same thing. We go two for two now in the similarity department, so... is Rust really any different then? There is a part of these examples that we skipped over - actually doing something with the values.</p> +<h2 id="moving-around-is-fun">Moving around is fun</h2> +<p>Let's expand on the last example. The scoping is not really important for that one, so we don't include it here.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// same thing, &#39;s&#39; is now an owner +</span><span> +</span><span style="color:#8959a8;">let</span><span> s2 </span><span style="color:#3e999f;">=</span><span> s; </span><span style="color:#999999;">// easy, &#39;s2&#39; becomes another owner... right? +</span><span> +</span><span>println!(</span><span style="color:#718c00;">&quot;And the contents are: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s); </span><span style="color:#999999;">// this doesn&#39;t work, can you guess why? +</span></code></pre> +<p>At first glance everything looks great. If we write this code (well, an equivalent of it) in basically any other popular language, it will compile no issue - but it does not here and there's a good reason why.</p> +<p>To understand what's happening, we have to consult the rules again, rule 2 in particular. It says that there can only be one owner of any value at a given time. So, <code>s</code> and <code>s2</code> cannot own the same object. Okay, makes sense, but what is happening in this line then - <code>let s2 = s;</code>? Experience probably tells you that <code>s</code> just gets copied into <code>s2</code>, creating a new String object. That would result in each variable owning its very own instance of the string and each instance having exactly one owner. Sounds like everyone should be happy now, but wait - in that case the last line should work no issue, right? But it doesn't, so can't be a copy. Let's see now what the compiler actually has to say:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0382]: borrow of moved value: `s` +</span><span> --&gt; src/main.rs:6:42 +</span><span> | +</span><span>2 | let s = String::from(&quot;a string&quot;); +</span><span> | - move occurs because `s` has type `String`, which does not implement the `Copy` trait +</span><span>3 | +</span><span>4 | let s2 = s; +</span><span> | - value moved here +</span><span>5 | +</span><span>6 | println!(&quot;And the contents are: {}&quot;, s); +</span><span> | ^ value borrowed here after move +</span></code></pre> +<p><em>&quot;value moved here&quot;</em> - gotcha! So <code>s</code> is being moved to <code>s2</code>, which also means that <code>s2</code> now becomes the new owner of the string being moved and <code>s</code> cannot be used anymore. In Rust, the default method of passing values around is by move, not by copy. While it may sound a bit odd at first, it actually has some very interesting implications. But before we get to them, let's fix our code, so it compiles now. To do so, we have to explicitly tell Rust to make a copy by invoking the <code>clone</code> method:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// &#39;s&#39; is an owner +</span><span> +</span><span style="color:#8959a8;">let</span><span> s2 </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">clone</span><span>(); </span><span style="color:#999999;">// &#39;s2&#39; now contains its own copy +</span><span> +</span><span>println!(</span><span style="color:#718c00;">&quot;And the contents are: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s); </span><span style="color:#999999;">// success! +</span></code></pre> +<p>The compiler is happy now and so are we. The implicit move takes some getting used to, but the compiler is here to help us. Now, let's put the good, old C++ on the table again and compare the two lines:</p> +<div style="text-align: center"> +<p><code>let s2 = s;</code> is equivalent to <code>auto s2 = std::move(s);</code></p> +<p><code>let s2 = s.clone()</code> is equivalent to <code>auto s2 = s</code></p> +</div> +<p>There are a few important things to note here:</p> +<ul> +<li> +<p>Making a copy is oftentimes not cheap. Memory needs to be allocated and copied, and a call to the system has to be made. We should prefer to move things as much as possible to avoid this cost - in C++ we have a myriad of language features like <code>std::move</code> and <em>r-references</em> to achieve this. Every programmer worth their salt needs to be well versed in all of them to write efficient C++ code and simply forgetting one move can lead to significant performance loss (and this happens to even the most senior devs ever existing, let's not pretend). On the contrary, in Rust you need to make an effort to make a copy and that makes you very aware of the cost you're paying - something that we'll see quite a lot of in the language. Also, if you forget a clone there's no harm done - it just won't compile!</p> +</li> +<li> +<p>Hidden in all of this is another nice thing Rust gives us. In C++, nothing prevents you from using variables after they've been moved from, leading to unexpected errors in a more complex code. In Rust, that variable (in our case <code>s</code>) simply becomes invalid and the compiler gives us a nice error about it.</p> +</li> +</ul> +<h3 id="but-what-about-ints">But what about ints?</h3> +<p>A good question to ask. Copying primitives is cheap. And it's not convenient for the programmer to have to always write <code>.clone()</code> after every primitive. If we take a look at the error from the previous example:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>move occurs because `s` has type `String`, which does not implement the `Copy` trait` +</span></code></pre> +<p>It says that <code>s</code> was moved because the <code>String</code> type doesn't have the <code>Copy</code> trait. We will talk about traits more in depth in the future lessons, but what this basically means is that <code>String</code> is not specified to be copied by default. All primitive types (<code>i32</code>, <code>bool</code>, <code>f64</code>, <code>char</code>, etc.) and tuples consisting only of primitive types implement the <code>Copy</code> trait.</p> +<h3 id="exercise">Exercise</h3> +<p>How to fix that code?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, s); +</span><span>} +</span></code></pre> +<h2 id="let-s-borrow-some-books">Let's borrow some books</h2> +<p>We now know how to move things around and how to clone them if moving is not possible. But what if making a copy is unnecessary - maybe we just want to let someone look at our resource and keep on holding onto it once their done. Consider the following example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(book.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Book is still there: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>Cloning is pretty excessive here. Imagine recommending a book to your friend and instead of lending it to them for the weekend, you scan it and print an exact copy. Not the best way to go about it, is it? Thankfully, Rust allows us to access a resource without becoming an owner through the use of references and the <code>&amp;</code> operator. This is called a borrow.</p> +<p>The adjusted code should look like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>book); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Book is still there: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>As with everything, references are too, by default, immutable, which means that the <code>read_book</code> function is not able to modify that book passed into it. We can also borrow something mutably by specifying it both in the receiving function signature and the place it gets called. Maybe you want to have your book signed by its author?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">sign_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> String) { +</span><span> book.</span><span style="color:#4271ae;">push_str</span><span>(</span><span style="color:#718c00;">&quot; ~ Arthur Author&quot;</span><span>); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// note that the book has to be marked as mutable in the first place +</span><span> </span><span style="color:#8959a8;">let mut</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">sign_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> book); </span><span style="color:#999999;">// it&#39;s always clear when a parameter might get modified +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); </span><span style="color:#999999;">// book is now signed +</span><span>} +</span></code></pre> +<p>Pretty neat, but doesn't seem that safe right now. Let's try to surprise our friend:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">erase_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> String) { +</span><span> book.</span><span style="color:#4271ae;">clear</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>book; </span><span style="color:#999999;">// an immutable borrow +</span><span> +</span><span> </span><span style="color:#4271ae;">erase_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> book); </span><span style="color:#999999;">// a mutable borrow +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(r); </span><span style="color:#999999;">// would be pretty sad to open a blank book when it was not +</span><span> </span><span style="color:#999999;">// what we borrowed initially +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>Fortunately for us (and our poor friend just wanting to read), the compiler steps in and doesn't let us do that, printing the following message:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0502]: cannot borrow `book` as mutable because it is also borrowed as immutable +</span><span> --&gt; src/main.rs:14:14 +</span><span> | +</span><span>12 | let r = &amp;book; // an immutable borrow +</span><span> | ----- immutable borrow occurs here +</span><span>13 | +</span><span>14 | erase_book(&amp;mut book); // a mutable borrow +</span><span> | ^^^^^^^^^ mutable borrow occurs here +</span><span>15 | +</span><span>16 | read_book(r); // would be pretty sad to open a blank book when it was not +</span><span> | - immutable borrow later used here +</span></code></pre> +<p>This is where the famous borrow checker comes in. To keep things super safe, Rust clearly states what can and cannot be done with references and tracks their lifetimes. Exactly one of the following is always true for references to a given resource:</p> +<ul> +<li> +<p>There exists only one mutable reference and no immutable references, <strong>or</strong></p> +</li> +<li> +<p>There is any number of immutable references and no mutable ones.</p> +</li> +</ul> +<p>You may notice a parallel to the <em>readers - writers</em> problem from concurrent programming. In fact, the way Rust's borrow checker is designed lends itself incredibly well to preventing data race related issues.</p> +<h3 id="dangling-references">Dangling references</h3> +<p>Rust also checks for dangling references. If we try to compile the following code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> reference_to_nothing </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">dangle</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dangle</span><span>() -&gt; </span><span style="color:#3e999f;">&amp;</span><span>String { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;hello&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>s +</span><span>} +</span></code></pre> +<p>we will get an adequate error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0106]: missing lifetime specifier +</span><span> --&gt; src/main.rs:5:16 +</span><span> | +</span><span>5 | fn dangle() -&gt; &amp;String { +</span><span> | ^ expected named lifetime parameter +</span><span> | +</span><span> = help: this function&#39;s return type contains a borrowed value, but there is no value for it to be borrowed from +</span><span>help: consider using the `&#39;static` lifetime +</span><span> | +</span><span>5 | fn dangle() -&gt; &amp;&#39;static String { +</span><span> | ^^^^^^^^ +</span></code></pre> +<p>The message above suggests specifing a lifetime for the returned string. In Rust, the lifetime of each variable is also a part of its type, but we will talk more about it later.</p> +<h3 id="exercise-1">Exercise</h3> +<p>Our previous solution using <code>clone()</code> was pretty inefficient. How should this code look now?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, s.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, s.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, s); </span><span style="color:#999999;">// we could&#39;ve ommitted the clone() here. Why? +</span><span>} +</span></code></pre> +<h2 id="everyone-gets-a-slice">Everyone gets a slice</h2> +<p>The last part of working with references that we will cover in this lesson are slices. A <em>slice</em> in Rust is a view over continuous data. Let us start with a string slice - the <code>&amp;str</code> type.</p> +<p><em><strong>Note:</strong> for the purposes of these examples we assume we are working with ASCII strings. More comprehensive articles on handling strings are linked at the end of this lesson.</em></p> +<p>To create a string slice from the <code>String</code> object <code>s</code>, we can simply write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#f5871f;">1</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">3</span><span>]; </span><span style="color:#999999;">// creates a slice of length 2, starting with the character at index 1 +</span></code></pre> +<p>This makes use of the <code>&amp;</code> operator and Rust's range notation to specify the beginning and end of the slice. Thus, we can also write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#f5871f;">2</span><span style="color:#3e999f;">..</span><span>]; </span><span style="color:#999999;">// everything from index 2 till the end +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">1</span><span>]; </span><span style="color:#999999;">// only the first byte +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#3e999f;">..</span><span>]; </span><span style="color:#999999;">// the whole string as a slice +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">as_str</span><span>(); </span><span style="color:#999999;">// also the whole string +</span></code></pre> +<p>You might have noticed that we always built <code>String</code> values using the <code>from()</code> method and never actually used the string literals directly. What type is a string literal then? Turns out it's the new string slice we just learned about!</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;string literal&quot;</span><span>; +</span></code></pre> +<p>In fact, it makes a lot sense - string literals, after all, are not allocated on the heap, but rather placed in a special section of the resulting binary. It's only natural we just reference that place with a slice.</p> +<p>Slices can also be taken from arrays:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> array: [</span><span style="color:#8959a8;">i32</span><span>; </span><span style="color:#f5871f;">4</span><span>] </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">42</span><span>, </span><span style="color:#f5871f;">10</span><span>, </span><span style="color:#f5871f;">5</span><span>, </span><span style="color:#f5871f;">2</span><span>]; </span><span style="color:#999999;">// creates an array of four 32 bit integers +</span><span style="color:#8959a8;">let</span><span> slice: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">i32</span><span>] </span><span style="color:#3e999f;">= &amp;</span><span>array[</span><span style="color:#f5871f;">1</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">3</span><span>]; </span><span style="color:#999999;">// results in a slice [10, 5] +</span></code></pre> +<h3 id="exercise-2">Exercise</h3> +<p>Can this code still be improved from the previous version utilizing references? Think about the signature of <code>count_animals</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span>} +</span></code></pre> +<h3 id="further-reading">Further reading</h3> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/std/primitive.char.html">Char documentation</a></p> +</li> +<li> +<p><a href="https://fasterthanli.me/articles/working-with-strings-in-rust">Working with strings in Rust</a></p> +</li> +<li> +<p><a href="https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html">The Book, chapter 4</a></p> +</li> +</ul> + + + + + 2021L Project showcase + 2022-10-17T00:00:00+00:00 + 2022-10-17T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/project-showcase/ + + <h1 id="some-projects-from-the-previous-semester">(Some) projects from the previous semester</h1> +<h2 id="chat-app">Chat App</h2> +<p><a href="https://github.com/barteksad/Chat-App">GitHub</a></p> +<p>Bartłomiej Sadlej (GitHub: @barteksad email: sadlejbartek@gmail.com)</p> +<p>&quot;Chat app written in Rust with Postgress db. Allows users to create new accounts and channels and communicate within channel. All unseed messages from last login are delivered once logged in again.</p> +<p>By default server stats with one user named ADMIN with password ADMIN&quot;</p> +<p>tokio, serde, anyhow, thiserror, dashmap</p> +<h2 id="algorithm-visualizer">Algorithm Visualizer</h2> +<p><a href="https://github.com/algorithm-visualzier/algorithm-visualizer">GitHub</a></p> +<p>Mikołaj Piróg (mikolajpirog@gmail.com, GitHub: @aetn23), Mikołaj Wasiak (wasiak.mikolaj1@gmail.com, GitHub: @RudyMis)</p> +<p>Graph editor with algorithms visualization. Create and modify the graph using GUI, move it around using WSAD. To see an algorithm being run, simply click on a node, and select the desired algorithm. See video and/or GitHub page for further details.</p> +<p>Petgraph, egui-tetra, dyn_partial_eq</p> +<video src="/lessons/project-showcase/graph_vis_demo.h264" controls width="320" height="240"> +</video> +<h2 id="rustal-combat">Rustal Combat</h2> +<p><a href="https://github.com/Emilo77/RUSTAL-COMBAT">GitHub</a></p> +<p>Kamil Bugała (GiHub: @Emilo77)</p> +<p>Simple game in the style of Mortal Combat. Two players fight each other by using dashes. It is the 1 v 1 version, so far it is possible to play on a one computer.</p> +<p>Bevy</p> +<h2 id="rusty-dungeon">Rusty dungeon</h2> +<p><a href="https://github.com/Rusty-Studios/rusty-dungeon">GitHub</a></p> +<p>Barbara Rosiak (GitHub: @barosiak, email basiarosiak.7@gmail.com), Tomasz Kubica (GitHub: @Tomasz-Kubica, email: tomaszkubica4@gmail.com), Dawid Mędrek (GitHub: @dawidmd)</p> +<p>A 2D game written using Rust and Bevy Game Engine, in which the player has to shoot and defeat enemies on their way to the final boss, inspired by the Binding of Isaac.</p> +<p>Bevy</p> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/project-showcase/rusty-dungeon.png" alt="" /></p> +<h2 id="mariomim">MarioMIM</h2> +<p><a href="https://github.com/KatKlo/rust-MarioMIM">GitHub</a></p> +<p>Katarzyna Kloc (GitHub: @KatKlo, email: kk429317@students.mimuw.edu.pl, linkedin: https://www.linkedin.com/in/katarzyna-kloc-7a7503209/), +Patryk Bundyra (GitHub: PBundyra, email: pb429159@students.mimuw.edu.pl, linkedin: https://www.linkedin.com/in/pbundyra/)</p> +<p>Since the moment CLion has shown us the first segfaults, we wanted to create a computer game inspired by the student’s adventure of pursuing a Computer Science degree. MarioMIM is a platform game whose main goal is to... get a degree. We’ve implemented a game inspired by Super Mario Bros, but in the special University of Warsaw edition. In order to overcome bugs, the student can strengthen himself by drinking coffee or learning the best programming language in the world - Rust.</p> +<p>Bevy, Rapier, Kira</p> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/project-showcase/fail-menu.png" alt="" /> +<img src="https://mimuw-jnp2-rust.github.io/lessons/project-showcase/game.png" alt="" /></p> +<h2 id="sendino">Sendino</h2> +<p><a href="https://github.com/grzenow4/project-sendino">GitHub</a></p> +<p>Grzegorz Nowakowski (Github: @grzenow4, email: g.nowakowski@student.uw.edu.pl) with @izmael7 on Github</p> +<p>One room chat application with client-server model of communication. Many users can communicate at one time.</p> +<p>Tokio, serde, crossterm</p> +<h2 id="chatter">Chatter</h2> +<p><a href="https://github.com/kfernandez31/JNP2-Chatter">GitHub</a></p> +<p>Kacper Kramarz-Fernandez (GitHub: @kfernandez31, email: kacper.fernandez@gmail.com), +Jan Zembowicz (GitHub: @JWZ1996, email: janzembowicz@gmail.com)</p> +<p>Chatter is a simple multi-room command-line chat application that uses a two-protocol (HTTP + WS) communication style for high-efficiency.</p> +<p>Tokio, Warp, Serde, Hyper, among others</p> + + + + + Oragnizational lesson + 2022-10-10T00:00:00+00:00 + 2022-10-10T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/00-organizational/ + + <h1 id="jnp-3-rust">JNP 3: Rust</h1> +<p>We will be using <a href="https://classroom.github.com">Github Classroom</a> for task submission and <a href="https://discord.gg/j2JFAsj7">Discord</a> for discussions.</p> +<p>Our main learning/teaching resource will be <a href="https://doc.rust-lang.org/stable/book/">&quot;The Book&quot;</a>.</p> +<h2 id="grading">Grading</h2> +<ul> +<li>1/3 of the grade is based on small tasks. There will be approximately 1 task every two weeks and each task will be graded on a scale of 0 to 3.</li> +<li>2/3 of the grade is based on a big project. You can choose a topic yourself, but it must be accepted by me. The project has to be split into two parts. It can be done in groups of two (or bigger).</li> +<li>The grade may be increased by a bonus. You can get a bonus for: +<ul> +<li>Making a presentation about some advanced topic (const generics, futures, macros, etc.) or about architecture of a selected Rust open-source library</li> +<li>Contributing to a selected Rust open-source library</li> +<li>Contributing to this course's materials</li> +<li>Quizzes, homeworks, etc.</li> +</ul> +</li> +</ul> +<h2 id="project-deadlines">Project Deadlines</h2> +<ol> +<li>2022-11-11: Project ideas should be presented to me for further refining. If you wish to pair up with someone, now is the time to tell me.</li> +<li>2022-11-18: Final project ideas should be accepted by now.</li> +<li>2022-12-16: Deadline for submitting the first part of the project.</li> +<li>2023-01-13: Deadline for submitting the second and final part of the project.</li> +</ol> + + + + + Introduction to Rust + 2022-10-10T00:00:00+00:00 + 2022-10-10T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/ + + <p><img src="https://www.rust-lang.org/logos/rust-logo-blk.svg" alt="Logo" /></p> +<h1 id="a-language-empowering-everyone-to-build-reliable-and-efficient-software">A language empowering everyone to build reliable and efficient software.</h1> +<p>(<a href="https://rustacean.net/">unofficial logo</a>)</p> +<h2 id="why-use-rust">Why use Rust?</h2> +<ul> +<li>It is <strong>safe</strong> (compared to C++ for example, as we will see in a minute)</li> +<li>It is <strong>fast</strong> (because it is compiled to machine code)</li> +<li>It is ergonomic and pleasant to use (static typing, expressive type system, helpful compiler +warnings)</li> +<li>It +is <a href="https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-programming-scripting-and-markup-languages">loved by programmers</a></li> +<li>It provides excellent tooling</li> +</ul> +<h2 id="why-learn-rust">Why learn Rust?</h2> +<p>Even if you don't end up using Rust, learning it expands your horizons</p> +<ul> +<li>it helps especially with the awareness of what you can and can't do in concurrent applications</li> +<li>it helps you understand memory management and learn its good practices</li> +</ul> +<h2 id="why-not-to-learn-rust">Why not to learn Rust?</h2> +<ul> +<li>Some people say Rust is too hard to learn because of the borrow checker</li> +<li>Once you get to know Cargo you won't ever want to use a language without a built-in package +manager ;)</li> +<li>You will start hating C++</li> +</ul> +<h2 id="demos">Demos</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/cpp_meme.jpg" alt="Meme" /></p> +<p>Let's compare the same code written in <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/errors_demo.c">C</a>, <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/errors_demo.cpp">C++</a> +and <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/errors_demo.rs">Rust</a>.</p> +<h2 id="code-you-sent-me">Code you sent me!</h2> +<h3 id="aleksander-tudruj">Aleksander Tudruj</h3> +<pre data-lang="cpp" style="background-color:#ffffff;color:#4d4d4c;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;iostream&gt; +</span><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;unordered_map&gt; +</span><span> +</span><span style="color:#8959a8;">using </span><span>name </span><span style="color:#3e999f;">=</span><span> std::string; +</span><span style="color:#8959a8;">using </span><span>age </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">int</span><span>; +</span><span style="color:#8959a8;">using </span><span>person </span><span style="color:#3e999f;">=</span><span> std::pair&lt;name, age&gt;; +</span><span style="color:#8959a8;">using </span><span>address </span><span style="color:#3e999f;">=</span><span> std::string; +</span><span style="color:#8959a8;">using </span><span>address_book </span><span style="color:#3e999f;">=</span><span> std::unordered_map&lt;person, address&gt;; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_address_book</span><span>(</span><span style="color:#8959a8;">const</span><span> address_book </span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">book</span><span>) +</span><span>{ +</span><span> </span><span style="color:#8959a8;">for </span><span>(</span><span style="color:#8959a8;">const auto </span><span style="color:#3e999f;">&amp;</span><span>[person, address] </span><span style="color:#3e999f;">:</span><span> book) +</span><span> { +</span><span> std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> person.</span><span style="color:#c82829;">first </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&quot; is &quot; </span><span style="color:#3e999f;">&lt;&lt;</span><span> person.</span><span style="color:#c82829;">second </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&quot; years old and lives at &quot; </span><span style="color:#3e999f;">&lt;&lt;</span><span> address </span><span style="color:#3e999f;">&lt;&lt;</span><span> std::endl; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() +</span><span>{ +</span><span> +</span><span> address_book </span><span style="color:#c82829;">people</span><span style="color:#4271ae;">{}</span><span>; +</span><span> people.</span><span style="color:#c82829;">insert</span><span>({{</span><span style="color:#718c00;">&quot;John&quot;</span><span>, </span><span style="color:#f5871f;">20</span><span>}, </span><span style="color:#718c00;">&quot;221B Baker Street, London&quot;</span><span>}); +</span><span> people.</span><span style="color:#c82829;">insert</span><span>({{</span><span style="color:#718c00;">&quot;Mary&quot;</span><span>, </span><span style="color:#f5871f;">30</span><span>}, </span><span style="color:#718c00;">&quot;Avenue des Champs-Élysées, Paris&quot;</span><span>}); +</span><span> people.</span><span style="color:#c82829;">insert</span><span>({{</span><span style="color:#718c00;">&quot;Jack&quot;</span><span>, </span><span style="color:#f5871f;">73</span><span>}, </span><span style="color:#718c00;">&quot;Wall Street, New York&quot;</span><span>}); +</span><span> </span><span style="color:#c82829;">print_address_book</span><span style="color:#4271ae;">(people)</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">return </span><span style="color:#f5871f;">0</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/tudruj.cpp">tudruj.cpp</a>)</sub></p> +<h3 id="krystyna-gasinska">Krystyna Gasińska</h3> +<pre data-lang="python" style="background-color:#ffffff;color:#4d4d4c;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#999999;"># sample 1 - different ways of removing elements from the list while iterating +</span><span>list1 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list1)</span><span>: +</span><span> </span><span style="color:#8959a8;">del </span><span>item +</span><span>list1 +</span><span> +</span><span style="color:#999999;"># [1, 2, 3, 4] +</span><span> +</span><span>list2 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list2)</span><span>: +</span><span> </span><span style="color:#4271ae;">list2.</span><span style="color:#c82829;">remove</span><span style="color:#4271ae;">(item) +</span><span>list2 +</span><span> +</span><span style="color:#999999;"># [2, 4] +</span><span> +</span><span>list3 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list3[:])</span><span>: +</span><span> </span><span style="color:#4271ae;">list3.</span><span style="color:#c82829;">remove</span><span style="color:#4271ae;">(item) +</span><span>list3 +</span><span> +</span><span style="color:#999999;"># [] +</span><span> +</span><span>list4 </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>] +</span><span style="color:#8959a8;">for </span><span>idx, item </span><span style="color:#8959a8;">in </span><span style="color:#4271ae;">enumerate(list4)</span><span>: +</span><span> </span><span style="color:#4271ae;">list4.</span><span style="color:#c82829;">pop</span><span style="color:#4271ae;">(idx) +</span><span>list4 +</span><span> +</span><span style="color:#999999;"># [2, 4] +</span><span> +</span><span style="color:#999999;"># sample 2 - string interning +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc&quot; +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc&quot; +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&#39;&#39;</span><span style="color:#4271ae;">.</span><span style="color:#c82829;">join</span><span style="color:#4271ae;">([</span><span style="color:#718c00;">&#39;a&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;b&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;c&#39;</span><span style="color:#4271ae;">]) +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&#39;&#39;</span><span style="color:#4271ae;">.</span><span style="color:#c82829;">join</span><span style="color:#4271ae;">([</span><span style="color:#718c00;">&#39;a&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;b&#39;</span><span style="color:#4271ae;">, </span><span style="color:#718c00;">&#39;c&#39;</span><span style="color:#4271ae;">]) +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc!&quot; +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;abc!&quot; +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span style="color:#999999;"># sample 3 - chained operations +</span><span>(</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">False</span><span>) </span><span style="color:#3e999f;">in </span><span>[</span><span style="color:#f5871f;">False</span><span>] +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">== </span><span>(</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">in </span><span>[</span><span style="color:#f5871f;">False</span><span>]) +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">False </span><span style="color:#3e999f;">in </span><span>[</span><span style="color:#f5871f;">False</span><span>] </span><span style="color:#999999;"># unexpected... +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span style="color:#999999;"># sample 4 - is operator +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">256 +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">256 +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span>a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">257 +</span><span>b </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">257 +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># False +</span><span> +</span><span>a, b </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">257</span><span>, </span><span style="color:#f5871f;">257 +</span><span>a </span><span style="color:#3e999f;">is </span><span>b +</span><span> +</span><span style="color:#999999;"># True +</span><span> +</span><span style="color:#f5871f;">257 </span><span style="color:#3e999f;">is </span><span style="color:#f5871f;">257 +</span><span> +</span><span style="color:#999999;"># &lt;&gt;:1: SyntaxWarning: &quot;is&quot; with a literal. Did you mean &quot;==&quot;? +</span><span style="color:#999999;"># &lt;&gt;:1: SyntaxWarning: &quot;is&quot; with a literal. Did you mean &quot;==&quot;? +</span><span style="color:#999999;"># C:\Users\kgasinsk\AppData\Local\Temp\ipykernel_15776\331119389.py:1: SyntaxWarning: &quot;is&quot; with a literal. Did you mean &quot;==&quot;? +</span><span style="color:#999999;"># 257 is 257 +</span><span> +</span><span style="color:#999999;"># sample 5 - local variables +</span><span style="color:#8959a8;">def </span><span style="color:#4271ae;">f</span><span>(</span><span style="color:#f5871f;">trufel</span><span>): +</span><span> </span><span style="color:#8959a8;">if </span><span>trufel: +</span><span> y </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">1 +</span><span> y </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1 +</span><span> +</span><span style="color:#c82829;">f</span><span style="color:#4271ae;">(</span><span style="color:#f5871f;">True</span><span style="color:#4271ae;">) </span><span style="color:#999999;"># everything is fine +</span><span> +</span><span style="color:#c82829;">f</span><span style="color:#4271ae;">(</span><span style="color:#f5871f;">False</span><span style="color:#4271ae;">) </span><span style="color:#999999;"># gives error: local variable &#39;y&#39; referenced before assignment +</span><span> +</span><span style="color:#999999;"># --------------------------------------------------------------------------- +</span><span style="color:#999999;"># UnboundLocalError Traceback (most recent call last) +</span><span style="color:#999999;"># Input In [17], in &lt;cell line: 1&gt;() +</span><span style="color:#999999;"># ----&gt; 1 f(False) +</span><span> +</span><span style="color:#999999;"># Input In [15], in f(trufel) +</span><span style="color:#999999;"># 3 if trufel: +</span><span style="color:#999999;"># 4 y = 1 +</span><span style="color:#999999;"># ----&gt; 5 y += 1 +</span><span> +</span><span style="color:#999999;"># UnboundLocalError: local variable &#39;y&#39; referenced before assignment +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/gasinska.py">gasinska.py</a>)</sub></p> +<h3 id="antoni-koszowski">Antoni Koszowski</h3> +<pre data-lang="go" style="background-color:#ffffff;color:#4d4d4c;" class="language-go "><code class="language-go" data-lang="go"><span style="color:#999999;">// mutowalność jest wbudowana w język +</span><span> +</span><span style="color:#8959a8;">type </span><span>S </span><span style="color:#8959a8;">struct </span><span>{ +</span><span> </span><span style="color:#c82829;">A </span><span style="color:#c99e00;">string +</span><span> </span><span style="color:#c82829;">B </span><span>[]</span><span style="color:#c99e00;">string +</span><span>} +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#c82829;">x </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">S</span><span>{</span><span style="color:#718c00;">&quot;x-A&quot;</span><span>, []</span><span style="color:#c99e00;">string</span><span>{</span><span style="color:#718c00;">&quot;x-B&quot;</span><span>}} +</span><span> </span><span style="color:#c82829;">y </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">x </span><span style="color:#999999;">// copy the struct +</span><span> </span><span style="color:#c82829;">y</span><span>.</span><span style="color:#c82829;">A </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;y-A&quot; +</span><span> </span><span style="color:#c82829;">y</span><span>.</span><span style="color:#c82829;">B</span><span>[</span><span style="color:#f5871f;">0</span><span>] </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;y-B&quot; +</span><span> +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Println</span><span>(</span><span style="color:#c82829;">x</span><span>, </span><span style="color:#c82829;">y</span><span>) +</span><span> </span><span style="color:#999999;">// Outputs &quot;{x-A [y-B]} {y-A [y-B]}&quot; -- x was modified! +</span><span>} +</span><span> +</span><span style="color:#999999;">// slices i kwestia append +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">doStuff</span><span>(</span><span style="color:#f5871f;">value </span><span>[]</span><span style="color:#c99e00;">string</span><span>) { +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Printf</span><span>(</span><span style="color:#718c00;">&quot;value=</span><span style="color:#666969;">%v</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">value</span><span>) +</span><span> +</span><span> </span><span style="color:#c82829;">value2 </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">value</span><span>[:] +</span><span> </span><span style="color:#c82829;">value2 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">append</span><span>(</span><span style="color:#c82829;">value2</span><span>, </span><span style="color:#718c00;">&quot;b&quot;</span><span>) +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Printf</span><span>(</span><span style="color:#718c00;">&quot;value=</span><span style="color:#666969;">%v</span><span style="color:#718c00;">, value2=</span><span style="color:#666969;">%v</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">value</span><span>, </span><span style="color:#c82829;">value2</span><span>) +</span><span> +</span><span> </span><span style="color:#c82829;">value2</span><span>[</span><span style="color:#f5871f;">0</span><span>] </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;z&quot; +</span><span> </span><span style="color:#c82829;">fmt</span><span>.</span><span style="color:#c82829;">Printf</span><span>(</span><span style="color:#718c00;">&quot;value=</span><span style="color:#666969;">%v</span><span style="color:#718c00;">, value2=</span><span style="color:#666969;">%v</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">value</span><span>, </span><span style="color:#c82829;">value2</span><span>) +</span><span>} +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#c82829;">slice1 </span><span style="color:#3e999f;">:= </span><span>[]</span><span style="color:#c99e00;">string</span><span>{</span><span style="color:#718c00;">&quot;a&quot;</span><span>} </span><span style="color:#999999;">// length 1, capacity 1 +</span><span> +</span><span> </span><span style="color:#c82829;">doStuff</span><span>(</span><span style="color:#c82829;">slice1</span><span>) +</span><span> </span><span style="color:#999999;">// Output: +</span><span> </span><span style="color:#999999;">// value=[a] -- ok +</span><span> </span><span style="color:#999999;">// value=[a], value2=[a b] -- ok: value unchanged, value2 updated +</span><span> </span><span style="color:#999999;">// value=[a], value2=[z b] -- ok: value unchanged, value2 updated +</span><span> +</span><span> </span><span style="color:#c82829;">slice10 </span><span style="color:#3e999f;">:= </span><span style="color:#4271ae;">make</span><span>([]</span><span style="color:#c99e00;">string</span><span>, </span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">10</span><span>) </span><span style="color:#999999;">// length 1, capacity 10 +</span><span> </span><span style="color:#c82829;">slice10</span><span>[</span><span style="color:#f5871f;">0</span><span>] </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;a&quot; +</span><span> +</span><span> </span><span style="color:#c82829;">doStuff</span><span>(</span><span style="color:#c82829;">slice10</span><span>) +</span><span> </span><span style="color:#999999;">// Output: +</span><span> </span><span style="color:#999999;">// value=[a] -- ok +</span><span> </span><span style="color:#999999;">// value=[a], value2=[a b] -- ok: value unchanged, value2 updated +</span><span> </span><span style="color:#999999;">// value=[z], value2=[z b] -- WTF?!? value changed??? +</span><span>} +</span><span> +</span><span style="color:#999999;">// error handling +</span><span> +</span><span style="color:#c82829;">len</span><span>, </span><span style="color:#c82829;">err </span><span style="color:#3e999f;">:= </span><span style="color:#c82829;">reader</span><span>.</span><span style="color:#c82829;">Read</span><span>(</span><span style="color:#c82829;">bytes</span><span>) +</span><span style="color:#8959a8;">if </span><span style="color:#c82829;">err </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">nil </span><span>{ +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">err </span><span style="color:#3e999f;">== </span><span style="color:#c82829;">io</span><span>.</span><span style="color:#c82829;">EOF </span><span>{ +</span><span> </span><span style="color:#999999;">// All good, end of file +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#8959a8;">return </span><span style="color:#c82829;">err +</span><span> } +</span><span>} +</span><span> +</span><span> +</span><span style="color:#999999;">// interfejs nil +</span><span> +</span><span style="color:#8959a8;">type </span><span>Explodes </span><span style="color:#8959a8;">interface </span><span>{ +</span><span> </span><span style="color:#4271ae;">Bang</span><span>() +</span><span> </span><span style="color:#4271ae;">Boom</span><span>() +</span><span>} +</span><span> +</span><span style="color:#999999;">// Type Bomb implements Explodes +</span><span style="color:#8959a8;">type </span><span>Bomb </span><span style="color:#8959a8;">struct </span><span>{} +</span><span style="color:#8959a8;">func </span><span>(</span><span style="color:#3e999f;">*</span><span style="color:#8959a8;">Bomb</span><span>) </span><span style="color:#4271ae;">Bang</span><span>() {} +</span><span style="color:#8959a8;">func </span><span>(</span><span style="color:#8959a8;">Bomb</span><span>) </span><span style="color:#4271ae;">Boom</span><span>() {} +</span><span> +</span><span style="color:#8959a8;">func </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">var </span><span style="color:#c82829;">bomb </span><span style="color:#3e999f;">*</span><span style="color:#8959a8;">Bomb </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">nil +</span><span> </span><span style="color:#8959a8;">var </span><span style="color:#c82829;">explodes </span><span style="color:#8959a8;">Explodes </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">bomb +</span><span> </span><span style="color:#4271ae;">println</span><span>(</span><span style="color:#c82829;">bomb</span><span>, </span><span style="color:#c82829;">explodes</span><span>) </span><span style="color:#999999;">// &#39;0x0 (0x10a7060,0x0)&#39; +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">explodes </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">nil </span><span>{ +</span><span> </span><span style="color:#4271ae;">println</span><span>(</span><span style="color:#718c00;">&quot;Not nil!&quot;</span><span>) </span><span style="color:#999999;">// &#39;Not nil!&#39; What are we doing here?!?! +</span><span> </span><span style="color:#c82829;">explodes</span><span>.</span><span style="color:#c82829;">Bang</span><span>() </span><span style="color:#999999;">// works fine +</span><span> </span><span style="color:#c82829;">explodes</span><span>.</span><span style="color:#c82829;">Boom</span><span>() </span><span style="color:#999999;">// panic: value method main.Bomb.Boom called using nil *Bomb pointer +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#4271ae;">println</span><span>(</span><span style="color:#718c00;">&quot;nil!&quot;</span><span>) </span><span style="color:#999999;">// why don&#39;t we end up here? +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// ubogie struktury danych, takie customowe tracą type safety m.in poprzez castowanie do interface{} +</span><span style="color:#999999;">// kiedyś brak generyków, choć teraz w znacznym stopniu problem został rozwiązany. +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/koszowski.go">koszowski.go</a>)</sub></p> +<h3 id="mieszko-grodzicki">Mieszko Grodzicki</h3> +<pre data-lang="python" style="background-color:#ffffff;color:#4d4d4c;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#8959a8;">def </span><span style="color:#4271ae;">add_contents</span><span>(</span><span style="color:#f5871f;">input_list</span><span>, </span><span style="color:#f5871f;">contents</span><span style="color:#3e999f;">=</span><span>[]): +</span><span> </span><span style="color:#8959a8;">for </span><span>val </span><span style="color:#8959a8;">in </span><span>input_list: +</span><span> </span><span style="color:#4271ae;">contents.</span><span style="color:#c82829;">append</span><span style="color:#4271ae;">(val) +</span><span> </span><span style="color:#8959a8;">return </span><span>contents +</span><span> +</span><span style="color:#4271ae;">print(</span><span style="color:#c82829;">add_contents</span><span style="color:#4271ae;">([</span><span style="color:#f5871f;">1</span><span style="color:#4271ae;">])) </span><span style="color:#999999;"># [1] +</span><span style="color:#4271ae;">print(</span><span style="color:#c82829;">add_contents</span><span style="color:#4271ae;">([</span><span style="color:#f5871f;">2</span><span style="color:#4271ae;">])) </span><span style="color:#999999;"># [1, 2] +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/grodzicki.py">grodzicki.py</a>)</sub></p> +<h2 id="installing-rust">Installing Rust</h2> +<ul> +<li><a href="https://rustup.rs/">Rustup</a></li> +<li>Setup an IDE +<ul> +<li><a href="https://www.jetbrains.com/clion/">CLion</a> (you can get +it <a href="https://www.jetbrains.com/community/education/">for free</a>) +and <a href="https://intellij-rust.github.io/">Intellij-Rust</a></li> +<li><a href="https://code.visualstudio.com/">VSCode</a> +and <a href="https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer">rust-analyzer</a></li> +<li>rust-analyzer also works +with <a href="https://rust-analyzer.github.io/manual.html#installation">other IDEs</a></li> +</ul> +</li> +</ul> +<h2 id="useful-tools">Useful tools</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/clippy.jpg" alt="Clippy" /></p> +<ul> +<li><code>cargo clippy</code> (for static analysis)</li> +<li>there's also <code>cargo check</code>, but it's less powerful than clippy</li> +<li><code>cargo fmt</code> (for code formatting)</li> +</ul> +<h3 id="rust-playground">Rust Playground</h3> +<ul> +<li><a href="https://play.rust-lang.org/">online Rust compiler</a></li> +</ul> +<h2 id="hello-world">Hello world</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;World&quot;</span><span>; +</span><span> println!(</span><span style="color:#718c00;">&quot;Hello, </span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, name); </span><span style="color:#999999;">// using the println! macro +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/hello_world.rs">hello_world.rs</a>)</sub></p> +<h3 id="variables">Variables</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40</span><span>; </span><span style="color:#999999;">// inferred type +</span><span> </span><span style="color:#8959a8;">let</span><span> y: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">100</span><span>; </span><span style="color:#999999;">// specified type +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40 </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">2</span><span>; </span><span style="color:#999999;">// shadowing +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x); </span><span style="color:#999999;">// prints 42 +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// x = 0; // compilation error, variables are by default immutable +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40</span><span>; </span><span style="color:#999999;">// declare as mutable +</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#999999;">// now we can reassign +</span><span> +</span><span> x </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; </span><span style="color:#999999;">// x = x + 1 +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/variables.rs">variables.rs</a>)</sub></p> +<h3 id="conditionals">Conditionals</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">42 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is 42&quot;</span><span>); +</span><span> } </span><span style="color:#8959a8;">else if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">43 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is 43&quot;</span><span>); +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is not 42 or 43&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// we can also use ifs as expressions +</span><span> </span><span style="color:#8959a8;">let</span><span> a_or_b </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;a&quot; </span><span style="color:#999999;">// notice no semicolon at the end +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;b&quot; +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/conditionals.rs">conditionals.rs</a>)</sub></p> +<h3 id="loops">Loops</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;i is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, i); </span><span style="color:#999999;">// i in [0, 10) +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">while</span><span> x </span><span style="color:#3e999f;">&lt; </span><span style="color:#f5871f;">50 </span><span>{ +</span><span> x </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> y </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let mut</span><span> iterations </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> iterations </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> iterations </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#8959a8;">continue</span><span>; +</span><span> } +</span><span> y </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> y </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// we can use labels to refer to a specific loop +</span><span> </span><span style="color:#8959a8;">let mut</span><span> count </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> &#39;counting_up: </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> remaining </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">10</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> remaining </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">9 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> </span><span style="color:#8959a8;">if</span><span> count </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">2 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break &#39;counting_up</span><span>; </span><span style="color:#999999;">// ends the outer loop +</span><span> } +</span><span> remaining </span><span style="color:#3e999f;">-= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> count </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use break with a value. +</span><span> </span><span style="color:#999999;">// Because loops are expressions too, +</span><span> </span><span style="color:#999999;">// the value we break with will be returned from the functions +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> value </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> counter </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break </span><span style="color:#f5871f;">32</span><span>; +</span><span> } +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/loops.rs">loops.rs</a>)</sub></p> +<h3 id="functions">Functions</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">get_5</span><span>() -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#f5871f;">5 </span><span style="color:#999999;">// we could also write &quot;return 5;&quot; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">print_sum</span><span>(</span><span style="color:#f5871f;">a</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">b</span><span>: </span><span style="color:#8959a8;">u32</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;a + b = </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, a </span><span style="color:#3e999f;">+</span><span> b); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">100</span><span>; +</span><span> </span><span style="color:#4271ae;">print_sum</span><span>(a, </span><span style="color:#4271ae;">get_5</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2022Z/01-introduction/functions.rs">functions.rs</a>)</sub></p> +<h2 id="test-assignment-not-graded">Test assignment (not graded)</h2> +<p>Click <a href="https://classroom.github.com/a/P_z-gHH-">here</a></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/book/">The Book, chapters 1-3</a></li> +</ul> +<h2 id="additional-reading">Additional reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/rust-by-example/">Rust By Example</a></li> +</ul> + + + + + Macros + 2022-06-07T00:00:00+00:00 + 2022-06-07T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/14-macros/ + + <h2 id="reading">Reading</h2> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch19-06-macros.html">The Book, Chapter 19.5</a></p> +</li> +<li> +<p><a href="https://danielkeep.github.io/tlborm/book/README.html">Little Book of Macros</a></p> +</li> +<li> +<p><a href="https://github.com/dtolnay/proc-macro-workshop">Macro Workshop</a></p> +</li> +</ul> + + + + + Macros + 2022-06-07T00:00:00+00:00 + 2022-06-07T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/16-macros/ + + <h2 id="reading">Reading</h2> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch19-06-macros.html">The Book, Chapter 19.5</a></p> +</li> +<li> +<p><a href="https://danielkeep.github.io/tlborm/book/README.html">Little Book of Macros</a></p> +</li> +<li> +<p><a href="https://github.com/dtolnay/proc-macro-workshop">Macro Workshop</a></p> +</li> +</ul> + + + + + [Bonus] Rusty graphs + 2022-06-07T00:00:00+00:00 + 2022-06-07T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/b1-rusty-graphs/ + + <h2 id="introduction">Introduction</h2> +<p>We all had to deal with graphs in Rust, thanks to the task &quot;corpos&quot;. Handling the graphs the way that was intended - implementing adjacency list by using <code>Rc&lt;RefCell&lt;Node&gt;&gt;</code> - had its drawbacks: an endless stream of derefing, a risk of creating a reference cycle and this mysterious &quot;interior mutability&quot; mechanism.</p> +<h2 id="rc-madness">Rc madness</h2> +<p>To quickly recap why and how this works: <code>Rc&lt;&gt;</code> is a smart pointer that utilizes reference counting, similar to <code>shared_ptr&lt;&gt;</code> from C++. However, due to Rust's ownerships rules it does not allow us to mutate the data behind the pointer. That's why we don't actually point to the node itself - we hide it behind <code>RefCell&lt;&gt;</code> allowing us to mutate the data, by utilizing interior mutability pattern.</p> +<p>There are serval caveats, however. First, we lose compiler's help - it won't scream at us when we try to do something illegal. Speaking technically, when using <code>RefCell&lt;&gt;</code> Rust can no longer help us statically - it employs runtime checks to ensure ownership rules. The program will panic if something goes wrong, which is somewhat orthogonal to Rust's mission of catching bugs at compile time. Even if our program is bug-less, we still have to pay performance penalty, since runtime checks are not free.</p> +<p>Opinion: working with <code>Rc&lt;RefCell&lt;&gt;&gt;</code> in Rust feels very off, since it abandons some of the core designs goals of Rust - catching bugs at compile time and introducing runtime cost that other languages avoid. Not to mention the syntax which at time can be daunting. Can we do better?</p> +<h2 id="owning-the-graph">Owning the graph</h2> +<p>The problems encountered above arise from the same source: C/C++-like pointer structures don't go well with Rust. Sure, they can be done, but at what cost? Maybe instead of trying to force Rust into doing something it clearly does not want us to do, we should try different approach?</p> +<p>We could reason somewhat like this: if multiple mutable ownership is the problem, maybe let's abandon it altogether? What about a single object owning the whole graph?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">struct </span><span>Graph { +</span><span> </span><span style="color:#c82829;">nodes</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Node&gt;, +</span><span> </span><span style="color:#c82829;">edges</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Edge&gt;, +</span><span> </span><span style="color:#c82829;">highest_idx</span><span>: NodeIdx, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Node { +</span><span> </span><span style="color:#c82829;">idx</span><span>: NodeIdx, +</span><span> </span><span style="color:#c82829;">data</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Edge { +</span><span> </span><span style="color:#c82829;">idx1</span><span>: NodeIdx, +</span><span> </span><span style="color:#c82829;">idx2</span><span>: NodeIdx, +</span><span>} +</span></code></pre> +<p>Here we implement a graph as a single, non-recursive struct, that owns the whole graph. The nodes are identified by their index. This implementation has its disadvantages when compared to adjacency list, but it has one major advantage: it plays nice with Rust as a language.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub type </span><span>NodeIdx </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">usize</span><span>; +</span><span> +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Graph { +</span><span> </span><span style="color:#c82829;">nodes</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Node&gt;, +</span><span> </span><span style="color:#c82829;">edges</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Edge&gt;, +</span><span> </span><span style="color:#c82829;">highest_idx</span><span>: NodeIdx, +</span><span>} +</span><span> +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Node { +</span><span> </span><span style="color:#c82829;">idx</span><span>: NodeIdx, +</span><span> </span><span style="color:#c82829;">data</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Edge { +</span><span> </span><span style="color:#c82829;">idx1</span><span>: NodeIdx, +</span><span> </span><span style="color:#c82829;">idx2</span><span>: NodeIdx, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Graph { +</span><span> </span><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">new</span><span>() -&gt; Graph { +</span><span> Graph { nodes: </span><span style="color:#c99e00;">Vec</span><span>::new(), edges: </span><span style="color:#c99e00;">Vec</span><span>::new(), highest_idx: </span><span style="color:#f5871f;">0 </span><span>} +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">add_node</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">data</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) { +</span><span> </span><span style="color:#c82829;">self</span><span>.nodes.</span><span style="color:#4271ae;">push</span><span>(Node { idx: </span><span style="color:#c82829;">self</span><span>.highest_idx </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">1</span><span>, data: data.</span><span style="color:#4271ae;">to_string</span><span>() }); +</span><span> </span><span style="color:#c82829;">self</span><span>.highest_idx </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">add_edge</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">idx1</span><span>: NodeIdx, </span><span style="color:#f5871f;">idx2</span><span>: NodeIdx) { +</span><span> </span><span style="color:#c82829;">self</span><span>.edges.</span><span style="color:#4271ae;">push</span><span>(Edge{idx1, idx2}); +</span><span> } +</span><span>} +</span></code></pre> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> graph </span><span style="color:#3e999f;">= </span><span>Graph::new(); +</span><span> +</span><span> graph.</span><span style="color:#4271ae;">add_node</span><span>(</span><span style="color:#718c00;">&quot;123&quot;</span><span>); +</span><span> +</span><span> graph.</span><span style="color:#4271ae;">add_edge</span><span>(</span><span style="color:#f5871f;">0</span><span>, </span><span style="color:#f5871f;">0</span><span>); +</span><span> +</span><span>} +</span></code></pre> +<p>This implementation has its problems of algorithmic nature (problematic removal and so on), but it plays nice with Rust. There is no runtime penalty and we enable compiler to help us. It also is not a syntactic nightmare.</p> +<h2 id="real-world-solution">Real-world solution</h2> +<p>If one tries to implement graphs in Rust and embarks on a Google journey how to exactly do it, they will find that the go-to answer is: it's a nightmare, use Petgraph. It's a sensible route to choose - Petgraph really simplifies things. In fact my team has done exactly that with our final program. Let's dive deeper into how Petgraph does its magic:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>Graph&lt;N, E, Ty = Directed, Ix = DefaultIx&gt; { +</span><span> </span><span style="color:#c82829;">nodes</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Node&lt;N, Ix&gt;&gt;, +</span><span> </span><span style="color:#c82829;">edges</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Edge&lt;E, Ix&gt;&gt;, +</span><span> </span><span style="color:#c82829;">ty</span><span>: PhantomData&lt;Ty&gt;, +</span><span>} +</span></code></pre> +<p>Huh, this is isomorphic to what's been discussed above. Maybe the next one will be different?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span> </span><span style="color:#8959a8;">pub struct </span><span>GraphMap&lt;N, E, Ty&gt; { +</span><span> </span><span style="color:#c82829;">nodes</span><span>: IndexMap&lt;N, </span><span style="color:#c99e00;">Vec</span><span>&lt;(N, CompactDirection)&gt;&gt;, +</span><span> </span><span style="color:#c82829;">edges</span><span>: IndexMap&lt;(N, N), E&gt;, +</span><span> </span><span style="color:#c82829;">ty</span><span>: PhantomData&lt;Ty&gt;, +</span><span>} +</span></code></pre> +<p>At first glance it is, but if we learn that <code>IndexMap</code> is a crate that essentially provides a map, we see that this example also is similar to the previous one (in a sense of using arena allocation [region-based memory management]).</p> +<p>One last representation to go:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>MatrixGraph&lt;N, E, Ty = Directed, Null: Nullable&lt;Wrapped = E&gt; = </span><span style="color:#c99e00;">Option</span><span>&lt;E&gt;, Ix = DefaultIx&gt; +</span><span>{ +</span><span> </span><span style="color:#c82829;">node_adjacencies</span><span>: </span><span style="color:#c99e00;">Vec</span><span>&lt;Null&gt;, +</span><span> </span><span style="color:#c82829;">node_capacity</span><span>: </span><span style="color:#8959a8;">usize</span><span>, +</span><span> </span><span style="color:#c82829;">nodes</span><span>: IdStorage&lt;N&gt;, +</span><span> </span><span style="color:#c82829;">nb_edges</span><span>: </span><span style="color:#8959a8;">usize</span><span>, +</span><span> </span><span style="color:#c82829;">ty</span><span>: PhantomData&lt;Ty&gt;, +</span><span> </span><span style="color:#c82829;">ix</span><span>: PhantomData&lt;Ix&gt;, +</span><span>} +</span></code></pre> +<p>This representations uses flattened 2D array to store the graph. No pointers in sight.</p> +<p>Of course, those representations are not ideal: they have their issues. To name a few: <code>Graph</code> is problematic when it comes to frequent removals of nodes or edges - since they are stored in <code>Vec</code>, one has to either put some kind of placeholder in place of node/edge (which is not very Rusty) or copy the whole array (which is slow). <code>GraphMap</code> mitigates this issues by using hash map to store the graph, but that introduces some requirements on the <code>Node</code> type: it must implement <code>Ord</code> as well as <code>Copy</code> and <code>Eq + Hash</code> - which may be suitable for integers, but not exactly for more complicated types. <code>MatrixGraph</code> takes up much space and, similarly to <code>Graph</code>, has its problems when it comes to removing nodes.</p> +<p>Yet, all this problems are not Rusty in nature - they hold across every programming language.</p> +<p>The point of talking about all this is not to argue that representations X is better in some algorithmic sense than Y; it is to see that pointer based approach, which may work well in other language, is the hard one in Rust and results in a nightmarish code. The proof by Petgraph example shows that real world implementations avoid pointers - for a good reason.</p> +<p>Here's some Petgraph code in action:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dfs_helper</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">graph</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> Graph, </span><span style="color:#f5871f;">node_index</span><span>: NodeIndex) { +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">add_step</span><span>(AlgorithmStep::Node(NodeStep::new( +</span><span> node_index, +</span><span> NodeState::Queued, +</span><span> ))); +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(node) </span><span style="color:#3e999f;">=</span><span> graph.</span><span style="color:#4271ae;">node_weight_mut</span><span>(node_index) { +</span><span> node.</span><span style="color:#4271ae;">set_state</span><span>(NodeState::Queued) +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> walker </span><span style="color:#3e999f;">=</span><span> graph +</span><span> .</span><span style="color:#4271ae;">neighbors_directed</span><span>(node_index, Direction::Outgoing) +</span><span> .</span><span style="color:#4271ae;">detach</span><span>(); +</span><span> +</span><span> </span><span style="color:#8959a8;">while let </span><span style="color:#c99e00;">Some</span><span>((edge_idx, other_node_idx)) </span><span style="color:#3e999f;">=</span><span> walker.</span><span style="color:#4271ae;">next</span><span>(graph) { +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(other_state) </span><span style="color:#3e999f;">=</span><span> graph +</span><span> .</span><span style="color:#4271ae;">node_weight</span><span>(other_node_idx) +</span><span> .</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#f5871f;">node</span><span>| node.</span><span style="color:#4271ae;">get_state</span><span>()) +</span><span> { +</span><span> </span><span style="color:#8959a8;">if </span><span>matches!(other_state, NodeState::NotVisited) { +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">add_step</span><span>(AlgorithmStep::Edge(EdgeStep::new(edge_idx))); +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">dfs_helper</span><span>(graph, other_node_idx); +</span><span> } +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">add_step</span><span>(AlgorithmStep::Node(NodeStep::new( +</span><span> node_index, +</span><span> NodeState::Visited, +</span><span> ))); +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(node) </span><span style="color:#3e999f;">=</span><span> graph.</span><span style="color:#4271ae;">node_weight_mut</span><span>(node_index) { +</span><span> node.</span><span style="color:#4271ae;">set_state</span><span>(NodeState::Visited) +</span><span> } +</span><span>} +</span></code></pre> +<p>Sources:</p> +<p><a href="https://docs.rs/petgraph/latest/petgraph/index.html">Petgraph</a></p> +<p><a href="https://github.com/petgraph/petgraph">Petgraph's source code</a></p> +<p><a href="https://github.com/nrc/r4cppp/blob/master/graphs/README.md">Rust's dev post about graphs</a></p> +<p><a href="https://smallcultfollowing.com/babysteps/blog/2015/04/06/modeling-graphs-in-rust-using-vector-indices/">Another blog post about graphs</a></p> +<p>Author: Mikołaj Piróg</p> + + + + + Async: Part 2 + 2022-05-23T00:00:00+00:00 + 2022-05-23T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/13-async-2/ + + <h2 id="reinventing-futures">Reinventing futures</h2> +<p>We recently got our feet wet with the async/await functionality of Rust by using the Tokio library. With this basic understanding of what we expect out of <code>futures</code>, let's try to come up with their details ourselves.</p> +<p>We know that, when asked, a future can either give us a ready value or still be waiting for it. Asking about the future's result is called <em>polling</em>. Our future could look something like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>SimpleFuture { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt;; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">enum </span><span>Poll&lt;T&gt; { +</span><span> Ready(T), +</span><span> Pending, +</span><span>} +</span></code></pre> +<p>The <code>poll</code> method can be called to check for the result of the future. There is a flaw in this however - whatever is coordinating our future-based computations will have to constantly poll each of them in hope they are ready to do some work.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>SimpleFuture { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt;; +</span><span>} +</span><span> +</span></code></pre> +<p>We can solve this by attaching a callback to our polling. The <code>wake</code> function passed to <code>poll</code> can be used to notify whoever issued the poll that the future is ready to make some progress and should be polled.</p> +<p>Let's picture a quick example of how our <code>SimpleFuture</code> could be used.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>SocketRead&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> </span><span style="color:#c82829;">socket</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> Socket, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>SimpleFuture </span><span style="color:#8959a8;">for </span><span>SocketRead&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Vec</span><span>&lt;</span><span style="color:#8959a8;">u8</span><span>&gt;; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt; { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.socket.</span><span style="color:#4271ae;">has_data_to_read</span><span>() { +</span><span> </span><span style="color:#999999;">// The socket has data -- read it into a buffer and return it. +</span><span> Poll::Ready(</span><span style="color:#c82829;">self</span><span>.socket.</span><span style="color:#4271ae;">read_buf</span><span>()) +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#999999;">// The socket does not yet have data. +</span><span> </span><span style="color:#999999;">// +</span><span> </span><span style="color:#999999;">// Arrange for `wake` to be called once data is available. +</span><span> </span><span style="color:#999999;">// When data becomes available, `wake` will be called, and the +</span><span> </span><span style="color:#999999;">// user of this `Future` will know to call `poll` again and +</span><span> </span><span style="color:#999999;">// receive data. +</span><span> </span><span style="color:#c82829;">self</span><span>.socket.</span><span style="color:#4271ae;">set_readable_callback</span><span>(wake); +</span><span> Poll::Pending +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="combining-futures">Combining futures</h3> +<p>With the <code>SimpleFuture</code> at our disposal we can easily model more advanced concurrent computations.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#999999;">/// Concurrency is achieved via the fact that calls to `poll` each future +</span><span style="color:#999999;">/// may be interleaved, allowing each future to advance itself at its own pace. +</span><span style="color:#8959a8;">pub struct </span><span>Join&lt;FutureA, FutureB&gt; { +</span><span> </span><span style="color:#999999;">// Each field may contain a future that should be run to completion. +</span><span> </span><span style="color:#999999;">// If the future has already completed, the field is set to `None`. +</span><span> </span><span style="color:#999999;">// This prevents us from polling a future after it has completed, which +</span><span> </span><span style="color:#999999;">// would violate the contract of the `Future` trait. +</span><span> </span><span style="color:#c82829;">a</span><span>: </span><span style="color:#c99e00;">Option</span><span>&lt;FutureA&gt;, +</span><span> </span><span style="color:#c82829;">b</span><span>: </span><span style="color:#c99e00;">Option</span><span>&lt;FutureB&gt;, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;FutureA, FutureB&gt; SimpleFuture </span><span style="color:#8959a8;">for </span><span>Join&lt;FutureA, FutureB&gt; +</span><span style="color:#8959a8;">where +</span><span> FutureA: SimpleFuture&lt;Output = ()&gt;, +</span><span> FutureB: SimpleFuture&lt;Output = ()&gt;, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>(); +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt; { +</span><span> </span><span style="color:#999999;">// Attempt to complete future `a`. +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(a) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.a { +</span><span> </span><span style="color:#8959a8;">if let </span><span>Poll::Ready(()) </span><span style="color:#3e999f;">=</span><span> a.</span><span style="color:#4271ae;">poll</span><span>(wake) { +</span><span> </span><span style="color:#c82829;">self</span><span>.a.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Attempt to complete future `b`. +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(b) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.b { +</span><span> </span><span style="color:#8959a8;">if let </span><span>Poll::Ready(()) </span><span style="color:#3e999f;">=</span><span> b.</span><span style="color:#4271ae;">poll</span><span>(wake) { +</span><span> </span><span style="color:#c82829;">self</span><span>.b.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.a.</span><span style="color:#4271ae;">is_none</span><span>() </span><span style="color:#3e999f;">&amp;&amp; </span><span style="color:#c82829;">self</span><span>.b.</span><span style="color:#4271ae;">is_none</span><span>() { +</span><span> </span><span style="color:#999999;">// Both futures have completed -- we can return successfully +</span><span> Poll::Ready(()) +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#999999;">// One or both futures returned `Poll::Pending` and still have +</span><span> </span><span style="color:#999999;">// work to do. They will call `wake()` when progress can be made. +</span><span> Poll::Pending +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<p>We can also queue futures like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>AndThenFut&lt;FutureA, FutureB&gt; { +</span><span> </span><span style="color:#c82829;">first</span><span>: </span><span style="color:#c99e00;">Option</span><span>&lt;FutureA&gt;, +</span><span> </span><span style="color:#c82829;">second</span><span>: FutureB, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;FutureA, FutureB&gt; SimpleFuture </span><span style="color:#8959a8;">for </span><span>AndThenFut&lt;FutureA, FutureB&gt; +</span><span style="color:#8959a8;">where +</span><span> FutureA: SimpleFuture&lt;Output = ()&gt;, +</span><span> FutureB: SimpleFuture&lt;Output = ()&gt;, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>(); +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt; { +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(first) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.first { +</span><span> </span><span style="color:#8959a8;">match</span><span> first.</span><span style="color:#4271ae;">poll</span><span>(wake) { +</span><span> </span><span style="color:#999999;">// We&#39;ve completed the first future -- remove it and start on +</span><span> </span><span style="color:#999999;">// the second! +</span><span> Poll::Ready(()) </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c82829;">self</span><span>.first.</span><span style="color:#4271ae;">take</span><span>(), +</span><span> </span><span style="color:#999999;">// We couldn&#39;t yet complete the first future. +</span><span> Poll::Pending </span><span style="color:#3e999f;">=&gt; </span><span style="color:#8959a8;">return </span><span>Poll::Pending, +</span><span> }; +</span><span> } +</span><span> </span><span style="color:#999999;">// Now that the first future is done, attempt to complete the second. +</span><span> </span><span style="color:#c82829;">self</span><span>.second.</span><span style="color:#4271ae;">poll</span><span>(wake) +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="exercise">Exercise</h3> +<p>The last example assumes that both futures are already constructed. In practice, however, we often want to chain futures that use the results of their predecessors, like this - <code>get_breakfast().and_then(|food| eat(food));</code>. Try implementing this behavior by adding a new method to the <code>SimpleFuture</code> trait called <code>and_then</code> and something that models this sequential computation (like the previous <code>AndThenFut</code> future).</p> +<h3 id="the-real-deal">The real deal</h3> +<p>We weren't far from the actual way Rust's futures are structured. The <code>Future</code> trait looks as follows:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>Future { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>( +</span><span> </span><span style="color:#999999;">// Note the change from `&amp;mut self` to `Pin&lt;&amp;mut Self&gt;`: +</span><span> </span><span style="color:#f5871f;">self</span><span>: Pin&lt;</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut Self</span><span>&gt;, +</span><span> </span><span style="color:#999999;">// and the change from `wake: fn()` to `cx: &amp;mut Context&lt;&#39;_&gt;`: +</span><span> </span><span style="color:#f5871f;">cx</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>Context&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;, +</span><span> ) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt;; +</span><span>} +</span></code></pre> +<p>There are two differences here. Firstly, we use a context instead of a standalone <code>wake</code> method. Since this callback was just a simple function pointer, there was no way for it to hold any data pertaining to which future called it. +Secondly, we take <code>self</code> as a <code>Pin&lt;&gt;</code>. This enables us to create immovable futures - we will go into it later.</p> +<h2 id="coordinating-futures-waker-executor">Coordinating futures - waker &amp; executor</h2> +<h3 id="using-wakers-and-context">Using wakers and context</h3> +<p>We will follow the <a href="https://rust-lang.github.io/async-book/02_execution/03_wakeups.html">steps</a> in the book to make a future that runs a separate thread that sleeps for a given duration and only then returns a result.</p> +<h3 id="executor">Executor</h3> +<p>We will follow the <a href="https://rust-lang.github.io/async-book/02_execution/04_executor.html">steps</a> in the book to create our own executor to run our futures on.</p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://rust-lang.github.io/async-book/04_pinning/01_chapter.html">Pinning in detail</a></li> +<li><a href="https://doc.rust-lang.org/nightly/std/pin/index.html">Pinning in even more detail</a></li> +<li><a href="https://tokio.rs/tokio/tutorial/async">Async in depth</a></li> +</ul> +<h2 id="additional-reading">Additional reading</h2> +<ul> +<li><a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/">What color is your function</a></li> +<li><a href="https://fasterthanli.me/articles/pin-and-suffering">Pin and suffering</a></li> +<li><a href="https://fasterthanli.me/articles/understanding-rust-futures-by-going-way-too-deep">Understanding Rust futures by going way too deep</a></li> +<li><a href="https://eventhelix.com/rust/rust-to-assembly-async-await/">Desugaring and assembly of Rust async/await</a></li> +</ul> +<h2 id="assignment-7-graded">Assignment 7 (graded)</h2> +<p><a href="https://classroom.github.com/a/5g7J3TNh">Calculator</a></p> +<p>Deadline: 18.12.2024 23:59</p> + + + + + Async: Part 2 + 2022-05-23T00:00:00+00:00 + 2022-05-23T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/15-async-2/ + + <h2 id="reinventing-futures">Reinventing futures</h2> +<p>We recently got our feet wet with the async/await functionality of Rust by using the Tokio library. With this basic understanding of what we expect out of <code>futures</code>, let's try to come up with their details ourselves.</p> +<p>We know that, when asked, a future can either give us a ready value or still be waiting for it. Asking about the future's result is called <em>polling</em>. Our future could look something like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>SimpleFuture { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt;; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">enum </span><span>Poll&lt;T&gt; { +</span><span> Ready(T), +</span><span> Pending, +</span><span>} +</span></code></pre> +<p>The <code>poll</code> method can be called to check for the result of the future. There is a flaw in this however - whatever is coordinating our future-based computations will have to constantly poll each of them in hope they are ready to do some work.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>SimpleFuture { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt;; +</span><span>} +</span><span> +</span></code></pre> +<p>We can solve this by attaching a callback to our polling. The <code>wake</code> function passed to <code>poll</code> can be used to notify whoever issued the poll that the future is ready to make some progress and should be polled.</p> +<p>Let's picture a quick example of how our <code>SimpleFuture</code> could be used.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>SocketRead&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> </span><span style="color:#c82829;">socket</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> Socket, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>SimpleFuture </span><span style="color:#8959a8;">for </span><span>SocketRead&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Vec</span><span>&lt;</span><span style="color:#8959a8;">u8</span><span>&gt;; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt; { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.socket.</span><span style="color:#4271ae;">has_data_to_read</span><span>() { +</span><span> </span><span style="color:#999999;">// The socket has data -- read it into a buffer and return it. +</span><span> Poll::Ready(</span><span style="color:#c82829;">self</span><span>.socket.</span><span style="color:#4271ae;">read_buf</span><span>()) +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#999999;">// The socket does not yet have data. +</span><span> </span><span style="color:#999999;">// +</span><span> </span><span style="color:#999999;">// Arrange for `wake` to be called once data is available. +</span><span> </span><span style="color:#999999;">// When data becomes available, `wake` will be called, and the +</span><span> </span><span style="color:#999999;">// user of this `Future` will know to call `poll` again and +</span><span> </span><span style="color:#999999;">// receive data. +</span><span> </span><span style="color:#c82829;">self</span><span>.socket.</span><span style="color:#4271ae;">set_readable_callback</span><span>(wake); +</span><span> Poll::Pending +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="combining-futures">Combining futures</h3> +<p>With the <code>SimpleFuture</code> at our disposal we can easily model more advanced concurrent computations.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#999999;">/// Concurrency is achieved via the fact that calls to `poll` each future +</span><span style="color:#999999;">/// may be interleaved, allowing each future to advance itself at its own pace. +</span><span style="color:#8959a8;">pub struct </span><span>Join&lt;FutureA, FutureB&gt; { +</span><span> </span><span style="color:#999999;">// Each field may contain a future that should be run to completion. +</span><span> </span><span style="color:#999999;">// If the future has already completed, the field is set to `None`. +</span><span> </span><span style="color:#999999;">// This prevents us from polling a future after it has completed, which +</span><span> </span><span style="color:#999999;">// would violate the contract of the `Future` trait. +</span><span> </span><span style="color:#c82829;">a</span><span>: </span><span style="color:#c99e00;">Option</span><span>&lt;FutureA&gt;, +</span><span> </span><span style="color:#c82829;">b</span><span>: </span><span style="color:#c99e00;">Option</span><span>&lt;FutureB&gt;, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;FutureA, FutureB&gt; SimpleFuture </span><span style="color:#8959a8;">for </span><span>Join&lt;FutureA, FutureB&gt; +</span><span style="color:#8959a8;">where +</span><span> FutureA: SimpleFuture&lt;Output = ()&gt;, +</span><span> FutureB: SimpleFuture&lt;Output = ()&gt;, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>(); +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt; { +</span><span> </span><span style="color:#999999;">// Attempt to complete future `a`. +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(a) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.a { +</span><span> </span><span style="color:#8959a8;">if let </span><span>Poll::Ready(()) </span><span style="color:#3e999f;">=</span><span> a.</span><span style="color:#4271ae;">poll</span><span>(wake) { +</span><span> </span><span style="color:#c82829;">self</span><span>.a.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Attempt to complete future `b`. +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(b) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.b { +</span><span> </span><span style="color:#8959a8;">if let </span><span>Poll::Ready(()) </span><span style="color:#3e999f;">=</span><span> b.</span><span style="color:#4271ae;">poll</span><span>(wake) { +</span><span> </span><span style="color:#c82829;">self</span><span>.b.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.a.</span><span style="color:#4271ae;">is_none</span><span>() </span><span style="color:#3e999f;">&amp;&amp; </span><span style="color:#c82829;">self</span><span>.b.</span><span style="color:#4271ae;">is_none</span><span>() { +</span><span> </span><span style="color:#999999;">// Both futures have completed -- we can return successfully +</span><span> Poll::Ready(()) +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#999999;">// One or both futures returned `Poll::Pending` and still have +</span><span> </span><span style="color:#999999;">// work to do. They will call `wake()` when progress can be made. +</span><span> Poll::Pending +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<p>We can also queue futures like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>AndThenFut&lt;FutureA, FutureB&gt; { +</span><span> </span><span style="color:#c82829;">first</span><span>: </span><span style="color:#c99e00;">Option</span><span>&lt;FutureA&gt;, +</span><span> </span><span style="color:#c82829;">second</span><span>: FutureB, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;FutureA, FutureB&gt; SimpleFuture </span><span style="color:#8959a8;">for </span><span>AndThenFut&lt;FutureA, FutureB&gt; +</span><span style="color:#8959a8;">where +</span><span> FutureA: SimpleFuture&lt;Output = ()&gt;, +</span><span> FutureB: SimpleFuture&lt;Output = ()&gt;, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>(); +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">wake</span><span>: </span><span style="color:#8959a8;">fn</span><span>()) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt; { +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Some</span><span>(first) </span><span style="color:#3e999f;">= &amp;</span><span style="color:#8959a8;">mut </span><span style="color:#c82829;">self</span><span>.first { +</span><span> </span><span style="color:#8959a8;">match</span><span> first.</span><span style="color:#4271ae;">poll</span><span>(wake) { +</span><span> </span><span style="color:#999999;">// We&#39;ve completed the first future -- remove it and start on +</span><span> </span><span style="color:#999999;">// the second! +</span><span> Poll::Ready(()) </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c82829;">self</span><span>.first.</span><span style="color:#4271ae;">take</span><span>(), +</span><span> </span><span style="color:#999999;">// We couldn&#39;t yet complete the first future. +</span><span> Poll::Pending </span><span style="color:#3e999f;">=&gt; </span><span style="color:#8959a8;">return </span><span>Poll::Pending, +</span><span> }; +</span><span> } +</span><span> </span><span style="color:#999999;">// Now that the first future is done, attempt to complete the second. +</span><span> </span><span style="color:#c82829;">self</span><span>.second.</span><span style="color:#4271ae;">poll</span><span>(wake) +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="exercise">Exercise</h3> +<p>The last example assumes that both futures are already constructed. In practice, however, we often want to chain futures that use the results of their predecessors, like this - <code>get_breakfast().and_then(|food| eat(food));</code>. Try implementing this behavior by adding a new method to the <code>SimpleFuture</code> trait called <code>and_then</code> and something that models this sequential computation (like the previous <code>AndThenFut</code> future).</p> +<h3 id="the-real-deal">The real deal</h3> +<p>We weren't far from the actual way Rust's futures are structured. The <code>Future</code> trait looks as follows:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>Future { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">poll</span><span>( +</span><span> </span><span style="color:#999999;">// Note the change from `&amp;mut self` to `Pin&lt;&amp;mut Self&gt;`: +</span><span> </span><span style="color:#f5871f;">self</span><span>: Pin&lt;</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut Self</span><span>&gt;, +</span><span> </span><span style="color:#999999;">// and the change from `wake: fn()` to `cx: &amp;mut Context&lt;&#39;_&gt;`: +</span><span> </span><span style="color:#f5871f;">cx</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>Context&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;, +</span><span> ) -&gt; Poll&lt;</span><span style="color:#8959a8;">Self::</span><span>Output&gt;; +</span><span>} +</span></code></pre> +<p>There are two differences here. Firstly, we use a context instead of a standalone <code>wake</code> method. Since this callback was just a simple function pointer, there was no way for it to hold any data pertaining to which future called it. +Secondly, we take <code>self</code> as a <code>Pin&lt;&gt;</code>. This enables us to create immovable futures - we will go into it later.</p> +<h2 id="coordinating-futures-waker-executor">Coordinating futures - waker &amp; executor</h2> +<h3 id="using-wakers-and-context">Using wakers and context</h3> +<p>We will follow the <a href="https://rust-lang.github.io/async-book/02_execution/03_wakeups.html">steps</a> in the book to make a future that runs a separate thread that sleeps for a given duration and only then returns a result.</p> +<h3 id="executor">Executor</h3> +<p>We will follow the <a href="https://rust-lang.github.io/async-book/02_execution/04_executor.html">steps</a> in the book to create our own executor to run our futures on.</p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://rust-lang.github.io/async-book/04_pinning/01_chapter.html">Pinning in detail</a></li> +<li><a href="https://doc.rust-lang.org/nightly/std/pin/index.html">Pinning in even more detail</a></li> +<li><a href="https://tokio.rs/tokio/tutorial/async">Async in depth</a></li> +</ul> +<h2 id="additional-reading">Additional reading</h2> +<ul> +<li><a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/">What color is your function</a></li> +<li><a href="https://fasterthanli.me/articles/pin-and-suffering">Pin and suffering</a></li> +<li><a href="https://fasterthanli.me/articles/understanding-rust-futures-by-going-way-too-deep">Understanding Rust futures by going way too deep</a></li> +</ul> + + + + + Async: Part 1 + 2022-05-16T00:00:00+00:00 + 2022-05-16T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/14-async-1/ + + <h2 id="tokio">Tokio</h2> +<p>We'll use the <a href="https://tokio.rs/tokio/tutorial">Tokio tutorial</a> (chapters <code>Overview</code>-<code>Channels</code>).</p> +<h2 id="common-rust-lifetime-misconceptions">Common Rust Lifetime Misconceptions</h2> +<p>Please read <a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md">this blogpost</a>.</p> + + + + + Design patterns + 2022-05-09T00:00:00+00:00 + 2022-05-09T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/13-design-patterns/ + + <h2 id="object-oriented-programming-and-rust">Object-oriented programming and Rust</h2> +<p>The book has <a href="https://doc.rust-lang.org/stable/book/ch17-01-what-is-oo.html">a chapter dedicated to it</a>. +Especially the <a href="https://doc.rust-lang.org/stable/book/ch17-03-oo-design-patterns.html#encoding-states-and-behavior-as-types">&quot;typestate&quot;</a> pattern is very interesting. +You can read more about it <a href="http://cliffle.com/blog/rust-typestate/">here</a>.</p> +<h2 id="how-to-build-a-good-library">How to build a good library</h2> +<p><a href="https://rust-lang.github.io/api-guidelines/about.html">These guidelines</a> have been created by the Rust library team.</p> +<h2 id="how-to-handle-errors">How to handle errors</h2> +<p><a href="https://nick.groenen.me/posts/rust-error-handling/">This post</a> is from 2020, but the libraries it mentions (<code>anyhow</code> and <code>thiserror</code>) are still the most popular.</p> +<h2 id="serde">Serde</h2> +<p><a href="https://serde.rs/">Serde</a> is the most popular serialization library for Rust.</p> +<h2 id="assignment">Assignment</h2> +<p>This week's assignment is to write a distributed calculator. +The details will be announced later, but you will have to base your solution on the <a href="https://doc.rust-lang.org/stable/book/ch20-00-final-project-a-web-server.html">final project from the book</a>.</p> + + + + + Fearless concurrency + 2022-04-25T00:00:00+00:00 + 2022-04-25T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/12-concurrency/ + + <h2 id="parallelism-vs-concurrency">Parallelism vs Concurrency</h2> +<p>Concurrency is when tasks <strong>can make</strong> progress <strong>independently</strong> of each other.</p> +<p>Parallelism is when multiple tasks <strong>make</strong> progress <strong>at the same time</strong>.</p> +<h2 id="concurrency-models-in-rust">Concurrency models in Rust</h2> +<h3 id="threads">Threads</h3> +<p>Nothing unusual here.</p> +<p>Threads can be created with the <code>thread::spawn</code> function <a href="https://doc.rust-lang.org/std/thread/fn.spawn.html">docs - please read them!</a>.</p> +<p>This method returns a <code>JoinHandle&lt;T&gt;</code> which can be used to wait for the thread to finish. <code>T</code> is the type of the thread's return value.</p> +<h4 id="propagating-panics">Propagating panics</h4> +<p>In Rust a panic of one thread doesn't affect the other threads (similar to how Java handles exceptions in threads).</p> +<h4 id="closures">Closures</h4> +<p>Closures which are used to create threads must take ownership of any values they use. It can be forced with the <code>move</code> keyword.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::thread; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> v </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> handle </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move </span><span style="color:#3e999f;">|| </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;Here&#39;s a vector: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, v); +</span><span> }); +</span><span> +</span><span> handle.</span><span style="color:#4271ae;">join</span><span>().</span><span style="color:#4271ae;">unwrap</span><span>(); +</span><span>} +</span></code></pre> +<p>Normal ownership rules still apply. It means that we cannot mutate the vector in the spawned thread from the main thread!</p> +<p>But what if we need to share some state?</p> +<h3 id="message-passing">Message passing</h3> +<p>One possible way is to use message passing. We can use a blocking queue (called <code>mpsc</code> - <a href="https://doc.rust-lang.org/std/sync/mpsc/index.html">&quot;multi producer single consumer FIFO queue&quot;</a>) to do it. +We talked about blocking queues in the Concurrent programming class. In Rust, they are strongly-typed. Sending and receiving ends have different types.</p> +<h3 id="mutexes">Mutexes</h3> +<p>In Rust, a mutex <em>wraps</em> a value and makes it thread-safe. +Because it becomes a part of the type, it's impossible to access the underlying value in an unsynchronized manner. It is conceptually similar to the <code>RefCell</code> type.</p> +<p><code>Arc</code> is a smart pointer like <code>Rc</code> but it can be shared between threads.</p> +<p>Please read more about them in <a href="https://doc.rust-lang.org/stable/book/ch16-03-shared-state.html">the book</a>.</p> +<p><a href="https://doc.rust-lang.org/std/sync/struct.Mutex.html">The docs</a> also mention <code>poisoning</code>.</p> +<h3 id="rwlocks">RwLocks</h3> +<p><a href="https://doc.rust-lang.org/std/sync/struct.RwLock.html">RwLocks</a> are similar to mutexes, but they distinguish between read and write locks.</p> +<h2 id="send-and-sync">Send and Sync</h2> +<p>They are marker traits used to indicate that a type or a reference to it can be sent across threads. See the <a href="https://doc.rust-lang.org/nomicon/send-and-sync.html">nomicon</a> for more information.</p> +<h2 id="atomic-types">Atomic types</h2> +<p>Atomic types are described in <a href="https://doc.rust-lang.org/std/sync/atomic/">the docs</a>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::sync::Arc; +</span><span style="color:#8959a8;">use </span><span>std::sync::atomic::{AtomicUsize, Ordering}; +</span><span style="color:#8959a8;">use </span><span>std::{hint, thread}; +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(AtomicUsize::new(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span> </span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> spinlock_clone.</span><span style="color:#4271ae;">store</span><span>(</span><span style="color:#f5871f;">0</span><span>, Ordering::SeqCst); +</span><span> }); +</span><span> +</span><span> </span><span style="color:#999999;">// Wait for the other thread to release the lock +</span><span> </span><span style="color:#8959a8;">while</span><span> spinlock.</span><span style="color:#4271ae;">load</span><span>(Ordering::SeqCst) </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">if let </span><span style="color:#c99e00;">Err</span><span>(panic) </span><span style="color:#3e999f;">=</span><span> thread.</span><span style="color:#4271ae;">join</span><span>() { +</span><span> println!(</span><span style="color:#718c00;">&quot;Thread had an error: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, panic); +</span><span> } +</span><span>} +</span></code></pre> +<p>Note that <code>atomic</code> values don't have to be wrapped in a mutex when shared across threads.</p> +<h3 id="wait">Wait...</h3> +<p>If most types are <code>Sync + Send</code>, then what stops us from using a standard, non-atomic integer in the example above?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>spinlock_clone </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>}); +</span><span> +</span><span style="color:#8959a8;">while </span><span style="color:#3e999f;">*</span><span>spinlock </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span>} +</span></code></pre> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0594]: cannot assign to data in an `Arc` +</span><span> --&gt; src/main.rs:9:9 +</span><span> | +</span><span>9 | *spinlock_clone += 1; +</span><span> | ^^^^^^^^^^^^^^^^^^^^ cannot assign +</span><span> | +</span><span> = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc&lt;i32&gt;` +</span></code></pre> +<p>...so we would have to use a <code>RefCell</code> to be able to modify the value through a shared reference...</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> spinlock </span><span style="color:#3e999f;">= </span><span>Arc::new(RefCell::new(</span><span style="color:#f5871f;">1</span><span>)); +</span><span> +</span><span style="color:#8959a8;">let</span><span> spinlock_clone </span><span style="color:#3e999f;">= </span><span>Arc::clone(</span><span style="color:#3e999f;">&amp;</span><span>spinlock); +</span><span style="color:#8959a8;">let</span><span> thread </span><span style="color:#3e999f;">= </span><span>thread::spawn(</span><span style="color:#8959a8;">move</span><span style="color:#3e999f;">|| </span><span>{ +</span><span> </span><span style="color:#3e999f;">*</span><span>spinlock_clone.</span><span style="color:#4271ae;">borrow_mut</span><span>() </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>}); +</span><span> +</span><span style="color:#999999;">// Wait for the other thread to release the lock +</span><span style="color:#8959a8;">while </span><span style="color:#3e999f;">*</span><span>spinlock.</span><span style="color:#4271ae;">borrow</span><span>() </span><span style="color:#3e999f;">!= </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> hint::spin_loop(); +</span><span>} +</span></code></pre> +<p>...but <code>RefCell</code> isn't <code>Sync</code>:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0277]: `RefCell&lt;i32&gt;` cannot be shared between threads safely +</span><span> --&gt; src/main.rs:9:18 +</span><span> | +</span><span>9 | let thread = thread::spawn(move|| { +</span><span> | ^^^^^^^^^^^^^ `RefCell&lt;i32&gt;` cannot be shared between threads safely +</span><span> | +</span><span> = help: the trait `Sync` is not implemented for `RefCell&lt;i32&gt;` +</span><span> = note: required because of the requirements on the impl of `Send` for `Arc&lt;RefCell&lt;i32&gt;&gt;` +</span><span> = note: required because it appears within the type `[closure@src/main.rs:9:32: 11:6]` +</span><span>note: required by a bound in `spawn` +</span></code></pre> +<p>And that bound mentioned in the last line looks like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">spawn</span><span>&lt;F, T&gt;(</span><span style="color:#f5871f;">f</span><span>: F) -&gt; JoinHandle&lt;T&gt; </span><span style="color:#8959a8;">where +</span><span> F: FnOnce() -&gt; T, +</span><span> F: Send + </span><span style="color:#8959a8;">&#39;static</span><span>, +</span><span> T: Send + </span><span style="color:#8959a8;">&#39;static</span><span>, +</span></code></pre> +<h4 id="exercise-for-the-reader">Exercise for the reader</h4> +<p>Why is it impossible to share a reference to a <code>Mutex</code> between threads?</p> +<h2 id="data-parallelism-with-rayon">Data parallelism with Rayon</h2> +<p><a href="https://docs.rs/rayon/latest/rayon/">Rayon</a> is a library for parallelization of data processing. +It can be used to parallelize the execution of functions over a collection of data by switching the standard <code>Iterator</code> to a <code>ParallelIterator</code>. +It works very similar to <a href="https://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html#executing_streams_in_parallel">Java's parallel streams</a>.</p> +<p>Why do that? Because thread synchronization is hard! <a href="https://doc.rust-lang.org/nomicon/races.html">Rust prevents data races</a>, but <a href="https://users.rust-lang.org/t/deadlock-is-it-a-bug-or-is-it-intentional/1544">logical races and deadlocks are impossible to prevent!</a>!</p> +<p><a href="https://github.com/rayon-rs/rayon/blob/master/FAQ.md">Rayon's FAQ</a> is worth reading.</p> +<h2 id="assignment-5-graded">Assignment #5 (graded)</h2> +<p><a href="https://classroom.github.com/a/lKaeLu8O">Here</a> you can find the fifth graded assignment. The deadline for submissions is 04.05.2022.</p> + + + + + Small Task Feedback #3 + 2022-04-11T00:00:00+00:00 + 2022-04-11T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/11-feedback3/ + + <h2 id="iterators">Iterators</h2> +<h3 id="too-many-bools">Too many bools</h3> +<p>Many people implemented the InterleaveIterator like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">pub struct </span><span>InterleaveIterator&lt;I: </span><span style="color:#c99e00;">Iterator</span><span>, J: </span><span style="color:#c99e00;">Iterator</span><span>&gt; { +</span><span> </span><span style="color:#c82829;">iter1</span><span>: I, +</span><span> </span><span style="color:#c82829;">iter2</span><span>: J, +</span><span> </span><span style="color:#c82829;">not_finished1</span><span>: </span><span style="color:#8959a8;">bool</span><span>, +</span><span> </span><span style="color:#c82829;">not_finished2</span><span>: </span><span style="color:#8959a8;">bool</span><span>, +</span><span> </span><span style="color:#c82829;">turn_of_first</span><span>: </span><span style="color:#8959a8;">bool</span><span>, +</span><span>} +</span></code></pre> +<p>There's no need to use <code>bool</code>s to keep track of whether the iterators are finished. The contract of +the <code>Iterator</code> trait specifies that <code>next()</code></p> +<blockquote> +<p>returns None when iteration is finished. Individual iterator implementations may choose to resume iteration, +and so calling next() again may or may not eventually start returning Some(Item) again at some point.</p> +</blockquote> +<p>If you want to make sure that once the iterator returns None, it will always return None, you can +use the <code>fuse()</code> method.</p> +<h3 id="or-else">or_else</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;I, J&gt; Iterator </span><span style="color:#8959a8;">for </span><span>InterleaveIterator&lt;I, J&gt; +</span><span style="color:#999999;">// where etc. +</span><span>{ +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">next</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">Self::</span><span>Item&gt; { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> ret_val; +</span><span> +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#c82829;">self</span><span>.next_from_a { +</span><span> </span><span style="color:#f5871f;">true </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> ret_val </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.i.</span><span style="color:#4271ae;">next</span><span>(); +</span><span> </span><span style="color:#8959a8;">if</span><span> ret_val.</span><span style="color:#4271ae;">is_none</span><span>() { +</span><span> ret_val </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.j.</span><span style="color:#4271ae;">next</span><span>() +</span><span> } +</span><span> } +</span><span> </span><span style="color:#f5871f;">false </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> ret_val </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.j.</span><span style="color:#4271ae;">next</span><span>(); +</span><span> </span><span style="color:#8959a8;">if</span><span> ret_val.</span><span style="color:#4271ae;">is_none</span><span>() { +</span><span> ret_val </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self</span><span>.i.</span><span style="color:#4271ae;">next</span><span>() +</span><span> } +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#c82829;">self</span><span>.next_from_i </span><span style="color:#3e999f;">= !</span><span style="color:#c82829;">self</span><span>.next_from_i; +</span><span> +</span><span> ret_val +</span><span> } +</span><span>} +</span></code></pre> +<p>Even though in this definition we don't have the excessive <code>bool</code>s, +it can still be written a lot more concisely using <code>or_else</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;I, J&gt; Iterator </span><span style="color:#8959a8;">for </span><span>InterleaveIterator&lt;I, J&gt; +</span><span style="color:#999999;">// where etc. +</span><span>{ +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">next</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">Self::</span><span>Item&gt; { +</span><span> </span><span style="color:#c82829;">self</span><span>.next_from_i </span><span style="color:#3e999f;">= !</span><span style="color:#c82829;">self</span><span>.next_from_i; +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.next_from_i { +</span><span> </span><span style="color:#c82829;">self</span><span>.i.</span><span style="color:#4271ae;">next</span><span>().</span><span style="color:#4271ae;">or_else</span><span>(|| </span><span style="color:#c82829;">self</span><span>.j.</span><span style="color:#4271ae;">next</span><span>()) +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.j.</span><span style="color:#4271ae;">next</span><span>().</span><span style="color:#4271ae;">or_else</span><span>(|| </span><span style="color:#c82829;">self</span><span>.i.</span><span style="color:#4271ae;">next</span><span>()) +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="why-not-or">Why not <code>or</code>?</h3> +<p>The <code>or</code> method evaluates the argument even if it's not used (eager evaluation). +Because calling <code>self.i.next()</code> has side effects, this would create a bug.</p> +<h3 id="step-by">step_by</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Div&lt;</span><span style="color:#8959a8;">usize</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Shreds&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>Shreds&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">div</span><span>(</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">rhs</span><span>: </span><span style="color:#8959a8;">usize</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Output { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> shreds </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self +</span><span> .shreds +</span><span> .</span><span style="color:#4271ae;">into_iter</span><span>() +</span><span> .</span><span style="color:#4271ae;">fold</span><span>(vec![], |</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">acc</span><span>, </span><span style="color:#f5871f;">el</span><span>| { +</span><span> acc.</span><span style="color:#4271ae;">push</span><span>((el, acc.</span><span style="color:#4271ae;">len</span><span>())); +</span><span> acc +</span><span> }) +</span><span> .</span><span style="color:#4271ae;">filter</span><span>(|(_, </span><span style="color:#f5871f;">nr</span><span>)| nr </span><span style="color:#3e999f;">%</span><span> rhs </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0</span><span>) +</span><span> .</span><span style="color:#4271ae;">map</span><span>(|(</span><span style="color:#f5871f;">el</span><span>, _)| el) +</span><span> .</span><span style="color:#4271ae;">collect</span><span>(); +</span><span> Shreds { shreds } +</span><span> } +</span><span>} +</span></code></pre> +<p>Instead of <code>fold</code> we can use <code>enumerate</code> to pair each element with its index.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Div&lt;</span><span style="color:#8959a8;">usize</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Shreds&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>Shreds&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">div</span><span>(</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">rhs</span><span>: </span><span style="color:#8959a8;">usize</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Output { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> shreds </span><span style="color:#3e999f;">= </span><span style="color:#c82829;">self +</span><span> .shreds +</span><span> .</span><span style="color:#4271ae;">into_iter</span><span>() +</span><span> .</span><span style="color:#4271ae;">enumerate</span><span>() +</span><span> .</span><span style="color:#4271ae;">filter</span><span>(|(_, </span><span style="color:#f5871f;">nr</span><span>)| nr </span><span style="color:#3e999f;">%</span><span> rhs </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0</span><span>) +</span><span> .</span><span style="color:#4271ae;">map</span><span>(|(</span><span style="color:#f5871f;">el</span><span>, _)| el) +</span><span> .</span><span style="color:#4271ae;">collect</span><span>(); +</span><span> Shreds { shreds } +</span><span> } +</span><span>} +</span></code></pre> +<p>However, it can be simplified even more. What we're doing here is basically reimplementing +<code>step_by</code> :)</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; Div&lt;</span><span style="color:#8959a8;">usize</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Shreds&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Output </span><span style="color:#3e999f;">= </span><span>Shreds&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">div</span><span>(</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">rhs</span><span>: </span><span style="color:#8959a8;">usize</span><span>) -&gt; </span><span style="color:#8959a8;">Self::</span><span>Output { +</span><span> Shreds { +</span><span> shreds: </span><span style="color:#c82829;">self</span><span>.shreds.</span><span style="color:#4271ae;">into_iter</span><span>().</span><span style="color:#4271ae;">step_by</span><span>(rhs).</span><span style="color:#4271ae;">collect</span><span>(), +</span><span> } +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="what-s-collect">What's <code>collect()</code>?</h3> +<p>It's not magic. We can collect the elements of an iterator into any type which implements +the appropriate <code>FromIterator</code> <a href="https://doc.rust-lang.org/std/iter/trait.FromIterator.html">trait</a>.</p> +<h2 id="shredding-usize">Shredding usize</h2> +<p>Instead of</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">impl </span><span>Shredder </span><span style="color:#8959a8;">for </span><span>usize { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">shred</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; Shreds { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> elements </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Vec</span><span>::new(); +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">to_string</span><span>().</span><span style="color:#4271ae;">chars</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> dig </span><span style="color:#3e999f;">=</span><span> i </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">usize </span><span style="color:#3e999f;">- </span><span style="color:#718c00;">&#39;0&#39; </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">usize</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> val_dig </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">crate</span><span>::value::Digit::new(dig); +</span><span> elements.</span><span style="color:#4271ae;">push</span><span>(Value::Digit(val_dig)); +</span><span> } +</span><span> Shreds { elements } +</span><span> } +</span><span>} +</span></code></pre> +<p>it's better to use the modulo operator and division to get the digits. Why? Converting a number to +string requires an additional heap allocation.</p> +<h2 id="make-illegal-states-unrepresentable">Make illegal states unrepresentable</h2> +<p>Some people used an i8 or some other integer type to keep track of whose turn it is. But the only +values that were ever used were 0 and 1. It means that there was a lot of cases where the +program would panic. Making it possible to encode an illegal state is +a <a href="https://en.wiktionary.org/wiki/footgun">footgun</a>. Using a <code>bool</code> is a better choice. What if there are more than two states? We can define a custom enum then.</p> + + + + + Smart Pointers + 2022-04-10T00:00:00+00:00 + 2022-04-10T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/10-smart-pointers/ + + <h1 id="working-with-the-heap">Working with the heap</h1> +<p>So far we've only used heap allocated memory indirectly by working with containers such as vectors, maps or the <code>String</code> type, otherwise allocating our variables on the stack. We didn't really have to be aware of the fact that these collections used the heap, as all that memory management details were hidden away from us. In this lesson we'll take a closer look at what is really happening there and how we can do that ourselves.</p> +<p>To work with heap-allocated memory, Rust features <em>smart pointers</em>. You should have already heard this term as it is a very important feature in C++ and the concept is virtually the same here - they are wrappers around raw allocated memory that provide additional, safety-ensuring mechanism. What defines a smart pointer in Rust is generally the implementation of two traits: <code>Drop</code> and <code>Deref</code>.</p> +<p>The <code>Drop</code> trait is pretty straightforward as it consists of one method - <code>fn drop(&amp;mut self)</code> - that is, basically, the destructor, invoked during stack unwinding.</p> +<p>The <code>Deref</code> trait allows us to overload the dereference (<code>*</code>) operator.</p> +<h2 id="deref-coercion">Deref coercion</h2> +<p>Apart from enabling access to the underlying value, implementing the <code>Deref</code> trait enables Rust to perform <em>deref coercion</em> on the pointer - trying to remove as many levels of indirection as it can. What it means in practice is that we will be able to use it with any code working on plain references.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::ops::Deref; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>MyBox&lt;T&gt;(T); +</span><span> +</span><span style="color:#999999;">// We won&#39;t be allocating anything on the heap here as it is not important here. +</span><span style="color:#999999;">// We&#39;re only focusing on the dereference mechanisms. +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; MyBox&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: T) -&gt; MyBox&lt;T&gt; { +</span><span> MyBox(x) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; Deref </span><span style="color:#8959a8;">for </span><span>MyBox&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">type </span><span>Target </span><span style="color:#3e999f;">=</span><span> T; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">deref</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">Self::</span><span>Target { +</span><span> </span><span style="color:#3e999f;">&amp;</span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0 +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#f5871f;">name</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;Hello, </span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, name); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> int_box </span><span style="color:#3e999f;">= </span><span>MyBox::new(x); +</span><span> +</span><span> assert_eq!(</span><span style="color:#f5871f;">5</span><span>, </span><span style="color:#3e999f;">*</span><span>int_box); +</span><span> +</span><span> </span><span style="color:#999999;">// String also implements the `Deref` trait. +</span><span> </span><span style="color:#999999;">// In fact, String actually is a smart pointer. +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;I&#39;m a smart pointer too&quot;</span><span>); +</span><span> </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> +</span><span> </span><span style="color:#999999;">// Deref coercion can deal with multiple levels of indirection. +</span><span> </span><span style="color:#8959a8;">let</span><span> str_box </span><span style="color:#3e999f;">= </span><span>MyBox::new(</span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Rust&quot;</span><span>)); +</span><span> </span><span style="color:#4271ae;">hello</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>str_box); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/10-smart-pointers/deref_coercion.rs">deref_coercion.rs</a>)</sub></p> +<p>In general, there are three possible coercions that Rust can perform:</p> +<ul> +<li> +<p>From <code>&amp;T</code> to <code>&amp;U</code> when <code>T: Deref&lt;Target=U&gt;</code></p> +</li> +<li> +<p>From <code>&amp;mut T</code> to <code>&amp;mut U</code> when <code>T: DerefMut&lt;Target=U&gt;</code></p> +</li> +<li> +<p>From <code>&amp;mut T</code> to <code>&amp;U</code> when <code>T: Deref&lt;Target=U&gt;</code></p> +</li> +</ul> +<p>While the first two coercions are straightforward, the third one is possible because treating a mutable reference as an immutable one does not break the rules of ownership.</p> +<h1 id="box-simple-wrapper"><code>Box</code> - simple wrapper</h1> +<p>The <code>Box&lt;T&gt;</code> type is the most basic out of Rust's smart pointers, equivalent to C++'s <code>std::unique_ptr&lt;T&gt;</code>. It's a simple wrapper that makes sure the underlying memory gets allocated and freed properly.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">box_simple</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> b </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Box</span><span>::new(</span><span style="color:#f5871f;">5</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;b = </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, b); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">10 </span><span style="color:#3e999f;">+ *</span><span>b; +</span><span>} +</span><span> +</span><span style="color:#999999;">// `Box` gives us the indirection required to define +</span><span style="color:#999999;">// recursive types +</span><span>#[</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span style="color:#8959a8;">enum </span><span>List { +</span><span> Cons(</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#c99e00;">Box</span><span>&lt;List&gt;), +</span><span> Nil, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#4271ae;">box_simple</span><span>(); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/10-smart-pointers/box.rs">box.rs</a>)</sub></p> +<h1 id="reference-counting">Reference counting</h1> +<p>The <code>Rc&lt;T&gt;</code> type is the equivalent of <code>std::shared_ptr&lt;T&gt;</code> from C++. There is one caveat to this though - because we're creating multiple references to the same object, those references have to be immutable in accordance with the ownership rules.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::rc::Rc; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>LoudInt(</span><span style="color:#8959a8;">i32</span><span>); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Drop </span><span style="color:#8959a8;">for </span><span>LoudInt { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">drop</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[</span><span style="color:#666969;">{}</span><span style="color:#718c00;">] Farewell!&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> outer_ref; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> inner_ref </span><span style="color:#3e999f;">= </span><span>Rc::new(LoudInt(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// strong_count represents the number of owning references pointing +</span><span> </span><span style="color:#999999;">// to data +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> outer_ref </span><span style="color:#3e999f;">= </span><span>Rc::clone(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref); +</span><span> +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>outer_ref)); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>inner_ref), </span><span style="color:#f5871f;">2</span><span>); +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;The </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> still lives!&quot;</span><span>, outer_ref.</span><span style="color:#f5871f;">0</span><span>); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>outer_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/10-smart-pointers/ref_count.rs">ref_count.rs</a>)</sub></p> +<p>Rust also provides a non-owning pointer in the form of <code>Weak&lt;T&gt;</code> (equivalent to <code>std::weak_ptr&lt;T&gt;</code>) that can be obtained from an instance of <code>Rc&lt;T&gt;</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::rc::Rc; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>LoudInt(</span><span style="color:#8959a8;">i32</span><span>); +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Drop </span><span style="color:#8959a8;">for </span><span>LoudInt { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">drop</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[</span><span style="color:#666969;">{}</span><span style="color:#718c00;">] Farewell!&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> weak_ref; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> shared_ref </span><span style="color:#3e999f;">= </span><span>Rc::new(LoudInt(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// weak_count keeps track of the non-owning reference to the data +</span><span> assert_eq!(Rc::weak_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">0</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// `downgrade()` obtains a weak pointer to Rc&#39;s data +</span><span> weak_ref </span><span style="color:#3e999f;">= </span><span>Rc::downgrade(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref); +</span><span> +</span><span> assert_eq!(Rc::weak_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">1</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// In order to use the the data underneath the weak pointer +</span><span> </span><span style="color:#999999;">// we need to obtain a new shared pointer from it. +</span><span> </span><span style="color:#999999;">// The `upgrade()` method returns `Option&lt;Rc&lt;T&gt;&gt;`. +</span><span> </span><span style="color:#8959a8;">let</span><span> temp </span><span style="color:#3e999f;">=</span><span> weak_ref.</span><span style="color:#4271ae;">upgrade</span><span>(); +</span><span> assert_eq!(Rc::strong_count(</span><span style="color:#3e999f;">&amp;</span><span>shared_ref), </span><span style="color:#f5871f;">2</span><span>); +</span><span> println!(</span><span style="color:#718c00;">&quot;The value is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, temp.</span><span style="color:#4271ae;">unwrap</span><span>().</span><span style="color:#f5871f;">0</span><span>); +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;The value should be deallocated by now.&quot;</span><span>); +</span><span> matches!(weak_ref.</span><span style="color:#4271ae;">upgrade</span><span>(), </span><span style="color:#c99e00;">None</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/10-smart-pointers/weak_ref.rs">weak_ref.rs</a>)</sub></p> +<h1 id="mutating-the-immutable">Mutating the immutable</h1> +<p>Good examples and explanation of the inferior mutability pattern and runtime borrow checking can be found in the <a href="https://doc.rust-lang.org/book/ch15-05-interior-mutability.html">book</a>.</p> +<p>Alongisde the <code>RefCell&lt;T&gt;</code> type described above, there is an analogous <a href="https://doc.rust-lang.org/std/cell/struct.Cell.html"><code>Cell&lt;T&gt;</code></a> type that operates on values instead of references.</p> +<h1 id="obligatory-reading">Obligatory reading</h1> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch15-00-smart-pointers.html">The Book, chapter 15</a></p> +</li> +<li> +<p><a href="https://doc.rust-lang.org/std/borrow/enum.Cow.html">std::borrow::Cow</a>, a versatile copy-on-write smart pointer</p> +</li> +</ul> +<h1 id="additional-reading">Additional reading</h1> +<ul> +<li><a href="https://www.fpcomplete.com/blog/rust-asref-asderef/">On wrapped references</a></li> +</ul> + + + + + Small Task Feedback #2 + 2022-04-04T00:00:00+00:00 + 2022-04-04T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/09-feedback2/ + + <h2 id="result-combinators">Result combinators</h2> +<p>Rust's <code>Result</code> type implements a lot of methods that simplify working with the two variants of the enum, especially when we're only interested in one of them. These methods are called <em>combinators</em>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> res: </span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// `map` allows us to transform the value inside `Ok()`, +</span><span> </span><span style="color:#999999;">// while leaving the `Err` untouched +</span><span> assert_eq!(res.</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#f5871f;">v</span><span>| v </span><span style="color:#3e999f;">*</span><span> v), </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">25</span><span>)); +</span><span> +</span><span> res </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> assert_eq!(res.</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#f5871f;">v</span><span>| v </span><span style="color:#3e999f;">*</span><span> v), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// With most combinators there are mirrored ones that work on `Err` +</span><span> </span><span style="color:#999999;">// variants instead of `Ok`s. +</span><span> assert_eq!(res.</span><span style="color:#4271ae;">map_err</span><span>(|</span><span style="color:#f5871f;">v</span><span>| v </span><span style="color:#3e999f;">*</span><span> v), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">25</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// We can swap an `Ok` value for a different one with `and()`. +</span><span> </span><span style="color:#999999;">// Analogously for `Err` and `or()`. +</span><span> res </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> assert_eq!(res.</span><span style="color:#4271ae;">and</span><span>(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">100</span><span>)), </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">100</span><span>)); +</span><span> +</span><span> res </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> assert_eq!(res.</span><span style="color:#4271ae;">and</span><span>(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">100</span><span>)), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// `and_then()` and `or_else()` allow us to invoke functions +</span><span> </span><span style="color:#999999;">// only when the result is either an `Ok` or an `Err` respectively. +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">sq </span><span style="color:#3e999f;">= </span><span>|</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#8959a8;">i32</span><span>| -&gt; </span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#8959a8;">i32</span><span>&gt; { </span><span style="color:#c99e00;">Ok</span><span>(x </span><span style="color:#3e999f;">*</span><span> x) }; +</span><span> </span><span style="color:#8959a8;">let </span><span style="color:#4271ae;">err </span><span style="color:#3e999f;">= </span><span>|</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#8959a8;">i32</span><span>| -&gt; </span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#8959a8;">i32</span><span>&gt; { </span><span style="color:#c99e00;">Err</span><span>(x) }; +</span><span> +</span><span> assert_eq!(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>).</span><span style="color:#4271ae;">and_then</span><span>(sq).</span><span style="color:#4271ae;">and_then</span><span>(sq), </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">16</span><span>)); +</span><span> assert_eq!(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>).</span><span style="color:#4271ae;">and_then</span><span>(sq).</span><span style="color:#4271ae;">and_then</span><span>(err), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">4</span><span>)); +</span><span> assert_eq!(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>).</span><span style="color:#4271ae;">and_then</span><span>(err).</span><span style="color:#4271ae;">and_then</span><span>(sq), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> assert_eq!(</span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">3</span><span>).</span><span style="color:#4271ae;">and_then</span><span>(sq).</span><span style="color:#4271ae;">and_then</span><span>(sq), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> +</span><span> assert_eq!(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>).</span><span style="color:#4271ae;">or_else</span><span>(sq).</span><span style="color:#4271ae;">or_else</span><span>(sq), </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> assert_eq!(</span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>).</span><span style="color:#4271ae;">or_else</span><span>(err).</span><span style="color:#4271ae;">or_else</span><span>(sq), </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> assert_eq!(</span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">3</span><span>).</span><span style="color:#4271ae;">or_else</span><span>(sq).</span><span style="color:#4271ae;">or_else</span><span>(err), </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#f5871f;">9</span><span>)); +</span><span> assert_eq!(</span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">3</span><span>).</span><span style="color:#4271ae;">or_else</span><span>(err).</span><span style="color:#4271ae;">or_else</span><span>(err), </span><span style="color:#c99e00;">Err</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span>} +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/09-feedback2/combinators.rs">combinators.rs</a>)</sub></p> +<p>You can find more about the <code>Result</code> type and all its methods <a href="https://doc.rust-lang.org/std/result/enum.Result.html">here</a>.</p> +<h2 id="useful-hashmap-methods">Useful hashmap methods</h2> +<p>We can create a new hashmap in two ways in Rust - either an empty one using the <code>new()</code> method or from a list of key-value pairs using the <code>from()</code> method.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let mut</span><span> empty: HashMap&lt;</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>, </span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span>HashMap::new(); +</span><span style="color:#8959a8;">let</span><span> filled </span><span style="color:#3e999f;">= </span><span>HashMap::from([ +</span><span> (</span><span style="color:#718c00;">&quot;a&quot;</span><span>, </span><span style="color:#f5871f;">1</span><span>), +</span><span> (</span><span style="color:#718c00;">&quot;b&quot;</span><span>, </span><span style="color:#f5871f;">2</span><span>), +</span><span> (</span><span style="color:#718c00;">&quot;c&quot;</span><span>, </span><span style="color:#f5871f;">3</span><span>), +</span><span> (</span><span style="color:#718c00;">&quot;d&quot;</span><span>, </span><span style="color:#f5871f;">4</span><span>), +</span><span>]); +</span></code></pre> +<p><code>std::collections::Hashmap</code> implements the <code>IntoIterator</code> trait, but there are also other very handy methods for iterating over the collection. We can use the <code>values()</code> and <code>values_mut()</code> methods to just iterate over values inside the map and the <code>keys()</code> method to iterate only over the keys.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let mut</span><span> map </span><span style="color:#3e999f;">= </span><span>HashMap::from([(</span><span style="color:#718c00;">&quot;a&quot;</span><span>, </span><span style="color:#f5871f;">1</span><span>), (</span><span style="color:#718c00;">&quot;b&quot;</span><span>, </span><span style="color:#f5871f;">2</span><span>)]); +</span><span> +</span><span>map.</span><span style="color:#4271ae;">values</span><span>().</span><span style="color:#4271ae;">for_each</span><span>(|</span><span style="color:#f5871f;">v</span><span>| println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, v)); +</span><span> +</span><span style="color:#8959a8;">for</span><span> v </span><span style="color:#3e999f;">in</span><span> map.</span><span style="color:#4271ae;">values_mut</span><span>() { +</span><span> </span><span style="color:#3e999f;">*</span><span>v </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span>} +</span><span> +</span><span>map.</span><span style="color:#4271ae;">keys</span><span>().</span><span style="color:#4271ae;">filter</span><span>(|</span><span style="color:#f5871f;">key</span><span>| key.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">1</span><span>).</span><span style="color:#4271ae;">count</span><span>(); +</span></code></pre> +<p>We can also consume all the key-value pairs from the map using <code>drain()</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::collections::HashMap; +</span><span> +</span><span style="color:#8959a8;">let mut</span><span> a </span><span style="color:#3e999f;">= </span><span>HashMap::new(); +</span><span>a.</span><span style="color:#4271ae;">insert</span><span>(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#718c00;">&quot;a&quot;</span><span>); +</span><span>a.</span><span style="color:#4271ae;">insert</span><span>(</span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#718c00;">&quot;b&quot;</span><span>); +</span><span> +</span><span style="color:#8959a8;">for </span><span>(k, v) </span><span style="color:#3e999f;">in</span><span> a.</span><span style="color:#4271ae;">drain</span><span>().</span><span style="color:#4271ae;">take</span><span>(</span><span style="color:#f5871f;">1</span><span>) { +</span><span> assert!(k </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">||</span><span> k </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">2</span><span>); +</span><span> assert!(v </span><span style="color:#3e999f;">== </span><span style="color:#718c00;">&quot;a&quot; </span><span style="color:#3e999f;">||</span><span> v </span><span style="color:#3e999f;">== </span><span style="color:#718c00;">&quot;b&quot;</span><span>); +</span><span>} +</span><span> +</span><span>assert!(a.</span><span style="color:#4271ae;">is_empty</span><span>()); +</span></code></pre> +<p>In the previous feedback you can also read about the <code>Entry</code> enum and how to work with it to access and modify values in a hashmap.</p> +<h2 id="matches-macro"><code>matches!()</code> macro</h2> +<p>Rust has a very convenient macro for checking whether something matches a given pattern. You can read more about the <code>matches!()</code> macro <a href="https://doc.rust-lang.org/std/macro.matches.html">here</a>.</p> +<h2 id="assignment-4-graded">Assignment #4 (graded)</h2> +<p><a href="https://classroom.github.com/a/jL6DS9YM">Here</a> you can find the fourth graded assignment. Deadline for submissions is 12.04.2022.</p> + + + + + Small Task Feedback #1 + 2022-03-29T00:00:00+00:00 + 2022-03-29T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/07-feedback/ + + <h2 id="constructors">Constructors</h2> +<p>There are no &quot;constructors&quot; in Rust. +<a href="https://doc.rust-lang.org/nomicon/constructors.html">There is exactly one way to create an instance of a user-defined type: name +it and initialize all its fields at once.</a></p> +<p>However, we often write associated functions that act as constructors.</p> +<p>In the below example you may notice a new keyword - <code>pub</code>. In Rust, almost everything is <em>private</em> by default (exceptions being items in a public <code>trait</code> and enum variants in a public <code>enum</code>). That means that it can be accessed from within the module it has been declared in, but cannot be accessed from the outside. So far we only worked with a singular file and no additional modules (apart from <code>tests</code>) so we didn't have to worry about it.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">mod </span><span>one { +</span><span> </span><span style="color:#8959a8;">pub struct </span><span>Point { +</span><span> </span><span style="color:#c82829;">x</span><span>: </span><span style="color:#8959a8;">i32</span><span>, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">impl </span><span>Point { +</span><span> </span><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; Point { +</span><span> Point { x } +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">pub fn </span><span style="color:#4271ae;">x</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">impl </span><span>Default </span><span style="color:#8959a8;">for </span><span>Point { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">default</span><span>() -&gt; Point { +</span><span> Point { x: </span><span style="color:#f5871f;">10 </span><span>} +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// won&#39;t compile, can&#39;t initialize private fields +</span><span> </span><span style="color:#999999;">// let p = one::Point { +</span><span> </span><span style="color:#999999;">// x: 1, +</span><span> </span><span style="color:#999999;">// }; +</span><span> </span><span style="color:#8959a8;">let</span><span> p </span><span style="color:#3e999f;">= </span><span>one::Point::new(</span><span style="color:#f5871f;">1</span><span>); +</span><span> </span><span style="color:#999999;">// won&#39;t compile, x is private +</span><span> </span><span style="color:#999999;">// println!(&quot;{}&quot;, p.x); +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, p.</span><span style="color:#4271ae;">x</span><span>()); +</span><span> </span><span style="color:#8959a8;">let</span><span> p </span><span style="color:#3e999f;">= </span><span>one::Point::default(); +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, p.</span><span style="color:#4271ae;">x</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/07-feedback/constructor.rs">constructor.rs</a>)</sub></p> +<h2 id="field-initialization-shorthand">Field initialization shorthand</h2> +<p>Note that in the above example, we wrote</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Point { x } +</span></code></pre> +<p>instead of</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>Point { x: x } +</span></code></pre> +<h2 id="destructors">Destructors</h2> +<p>If we need a custom destructor, we can implement the <code>Drop</code> trait. +Read more <a href="https://doc.rust-lang.org/stable/reference/destructors.html">here</a>.</p> +<h2 id="naming">Naming</h2> +<p>Refer to <a href="https://rust-lang.github.io/api-guidelines/naming.html">this guideline</a> for naming conventions.</p> +<h2 id="underscore">Underscore</h2> +<p>Underscore is used to mark variables that are unused.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">example</span><span>(</span><span style="color:#f5871f;">used</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">_unused_param</span><span>: </span><span style="color:#8959a8;">i32</span><span>) { +</span><span> </span><span style="color:#8959a8;">let</span><span> _unused </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">match</span><span> used { +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>unimplemented!(), +</span><span> } +</span><span>} +</span></code></pre> +<p>It should not be used in other contexts.</p> +<h2 id="hashmap-entry">Hashmap entry</h2> +<p><a href="https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.entry">entry</a> is a convenient way to get a mutable reference to a value in a hashmap.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let mut</span><span> map </span><span style="color:#3e999f;">= </span><span>std::collections::HashMap::new(); +</span><span style="color:#3e999f;">*</span><span>map.</span><span style="color:#4271ae;">entry</span><span>(</span><span style="color:#718c00;">&quot;key&quot;</span><span>).</span><span style="color:#4271ae;">or_insert</span><span>(</span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span style="color:#3e999f;">*</span><span>map.</span><span style="color:#4271ae;">entry</span><span>(</span><span style="color:#718c00;">&quot;key&quot;</span><span>).</span><span style="color:#4271ae;">or_insert</span><span>(</span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span>assert_eq!(map[</span><span style="color:#718c00;">&quot;key&quot;</span><span>], </span><span style="color:#f5871f;">2</span><span>); +</span></code></pre> +<h2 id="number-conversions">Number conversions</h2> +<p>Number conversions are... not the most intuitive.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> small_number: </span><span style="color:#8959a8;">u32 </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">u32</span><span>::</span><span style="color:#666969;">MAX</span><span>; +</span><span> </span><span style="color:#999999;">// dbg!(small_number + 1); // this will panic (in debug builds, in release build it will wrap) +</span><span> assert_eq!(small_number </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">u8</span><span>, </span><span style="color:#f5871f;">255</span><span>); +</span><span> assert_eq!(small_number </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">i8</span><span>, </span><span style="color:#3e999f;">-</span><span style="color:#f5871f;">1</span><span>); +</span><span> assert_eq!(small_number </span><span style="color:#3e999f;">as </span><span style="color:#8959a8;">i64</span><span>, </span><span style="color:#f5871f;">4294967295</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> converted: </span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#8959a8;">i8</span><span>, </span><span style="color:#3e999f;">_</span><span>&gt; </span><span style="color:#3e999f;">=</span><span> small_number.</span><span style="color:#4271ae;">try_into</span><span>(); +</span><span> assert!(converted.</span><span style="color:#4271ae;">is_err</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/07-feedback/number_conversions.rs">number_conversions.rs</a>)</sub></p> +<h2 id="use-rustfmt-in-clion">Use rustfmt in Clion</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/07-feedback/rustfmt.png" alt="" /></p> +<h2 id="use-clippy-in-clion">Use clippy in Clion</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/07-feedback/clippy.png" alt="" /></p> +<h2 id="clippy-auto-fixing">Clippy auto-fixing</h2> +<p>Clippy can automagically fix some of the issues it detects if run with <code>cargo clippy --fix</code></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html">The Book, chapter 7</a></li> +</ul> + + + + + Closures and Iterators + 2022-03-27T00:00:00+00:00 + 2022-03-27T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/08-closures-iterators/ + + <h1 id="closures">Closures</h1> +<p>Closures (Polish: &quot;domknięcia&quot;) are anonymous functions that can access variables from the scope in which they were defined.</p> +<p>We'll go through the examples from <a href="https://doc.rust-lang.org/rust-by-example/fn/closures.html">Rust by Example</a>.</p> +<h1 id="iterators">Iterators</h1> +<p>In Rust, there is no hierarchy of types for collections (because there is no inheritance in general). +Instead, what makes a collection is that it can be iterated over.</p> +<p>We'll go through the official <a href="https://doc.rust-lang.org/stable/std/iter/">docs</a>. +Most methods are defined in the <a href="https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html">Iterator trait</a>.</p> +<h1 id="reading">Reading</h1> +<ul> +<li><a href="https://doc.rust-lang.org/book/ch12-00-an-io-project.html">The Book, chapter 12 (that's a project!)</a></li> +<li><a href="https://doc.rust-lang.org/book/ch13-00-functional-features.html">The Book, chapter 13</a></li> +<li><a href="https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html">The Book, chapter 14</a></li> +<li><a href="https://doc.rust-lang.org/stable/book/ch19-05-advanced-functions-and-closures.html">The Book, Advanced Functions and Closures</a></li> +<li><a href="https://doc.rust-lang.org/stable/book/ch19-03-advanced-traits.html">The Book, Advanced Traits</a></li> +</ul> +<h1 id="assignment-3-graded">Assignment #3 (graded)</h1> +<p><a href="https://classroom.github.com/a/OLqc7DAh">Here</a> you can find the third graded assignment. Deadline for submissions is 05.04.2022.</p> + + + + + Reasoning About Types + 2022-03-21T00:00:00+00:00 + 2022-03-21T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/ + + <h1 id="type-traits">Type traits</h1> +<p>Traits are a way to defined common behavior between different types. They can be compared to <em>interfaces</em> from many other mainstream languages or to typeclasses from Haskell, however, Rust is not an object-oriented language and there are some notable differences between type traits and typeclasses.</p> +<p>The way we describe behavior in Rust is through methods. Traits consist of a set of these methods which then should be implemented by a type. We've already encountered examples of these, like the <code>Clone</code> trait which specified that the <code>clone()</code> method can be called on some given type. Now, let's take a deeper look and try defining our own trait.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Summary { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>NewsArticle { +</span><span> </span><span style="color:#c82829;">headline</span><span>: String, +</span><span> </span><span style="color:#c82829;">location</span><span>: String, +</span><span> </span><span style="color:#c82829;">author</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>NewsArticle { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">, by </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.headline, </span><span style="color:#c82829;">self</span><span>.author, </span><span style="color:#c82829;">self</span><span>.location) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Tweet { +</span><span> </span><span style="color:#c82829;">username</span><span>: String, +</span><span> </span><span style="color:#c82829;">content</span><span>: String, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Summary </span><span style="color:#8959a8;">for </span><span>Tweet { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">summarize</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.username, </span><span style="color:#c82829;">self</span><span>.content) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> tweet </span><span style="color:#3e999f;">=</span><span> Tweet { +</span><span> username: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;horse_ebooks&quot;</span><span>), +</span><span> content: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;of course, as you probably already know, people&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;1 new tweet: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, tweet.</span><span style="color:#4271ae;">summarize</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/basic_trait.rs">basic_trait.rs</a>)</sub></p> +<h2 id="default-implementations">Default implementations</h2> +<p>Trait definitions can also be provided with default implementations of behaviors.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Upload { +</span><span> </span><span style="color:#c82829;">filename</span><span>: String, +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span style="color:#8959a8;">struct </span><span>Photo { +</span><span> </span><span style="color:#c82829;">filename</span><span>: String, +</span><span> </span><span style="color:#c82829;">width</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">height</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span>} +</span><span> +</span><span style="color:#8959a8;">trait </span><span>Description { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">describe</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;No description available.&quot;</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// All default implementations +</span><span style="color:#8959a8;">impl </span><span>Description </span><span style="color:#8959a8;">for </span><span>Upload {} +</span><span> +</span><span style="color:#999999;">// Default implementations can be overwritten +</span><span style="color:#8959a8;">impl </span><span>Description </span><span style="color:#8959a8;">for </span><span>Photo { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">describe</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; String { +</span><span> format!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;"> (</span><span style="color:#666969;">{}</span><span style="color:#718c00;"> x </span><span style="color:#666969;">{}</span><span style="color:#718c00;">)&quot;</span><span>, </span><span style="color:#c82829;">self</span><span>.filename, </span><span style="color:#c82829;">self</span><span>.width, </span><span style="color:#c82829;">self</span><span>.height) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// Default implementations can rely on methods with no defaults +</span><span style="color:#8959a8;">trait </span><span>Size { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">width</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32</span><span>; +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">height</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">size</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">width</span><span>() </span><span style="color:#3e999f;">* </span><span style="color:#c82829;">self</span><span>.</span><span style="color:#4271ae;">height</span><span>() +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Size </span><span style="color:#8959a8;">for </span><span>Photo { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">width</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.width +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">height</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.height +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Using default impl of `size()` +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> upload </span><span style="color:#3e999f;">=</span><span> Upload { +</span><span> filename: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;notes.txt&quot;</span><span>), +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Upload: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, upload.</span><span style="color:#4271ae;">describe</span><span>()); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> photo </span><span style="color:#3e999f;">=</span><span> Photo { +</span><span> filename: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;stock_crustacean.png&quot;</span><span>), +</span><span> width: </span><span style="color:#f5871f;">100</span><span>, +</span><span> height: </span><span style="color:#f5871f;">150</span><span>, +</span><span> }; +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Photo: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, photo.</span><span style="color:#4271ae;">describe</span><span>()); +</span><span> println!(</span><span style="color:#718c00;">&quot;Size: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, photo.</span><span style="color:#4271ae;">size</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/trait_default.rs">trait_default.rs</a>)</sub></p> +<h2 id="what-about-derive">What about <em>derive</em>?</h2> +<p>There is a trait-related thing we have used quite extensively and not explained yet, namely the <code>#[derive]</code> attribute. What it does is generate items (in our case a trait implementation) based on the given data definition (here a struct). Below you can find a list of derivable traits from the standard library. Writing derivation rules for user defined traits is also possible, but goes out of the scope of this lesson.</p> +<p>Derivable traits:</p> +<ul> +<li> +<p>Equality traits: <code>Eq</code>, <code>PartialEq</code> and comparison traits: <code>Ord</code> and <code>PartialOrd</code>. The <code>Partial-</code> versions exist because there are types which don't fulfill the reflexivity requirement of equality (<code>NaN != NaN</code>) or do not form a total order (<code> NaN &lt; 0.0 == false</code> and <code>NaN &gt;= 0.0 == false</code>).</p> +</li> +<li> +<p>Data duplication traits: <code>Clone</code> and <code>Copy</code></p> +</li> +<li> +<p><code>Hash</code> - allows using values of that type as keys in a hashmap</p> +</li> +<li> +<p><code>Default</code> - provides a zero-arg constructor function</p> +</li> +<li> +<p><code>Debug</code> - provides a formatting of the value which can be used in debugging context. It should <em>NOT</em> be implemented manually. In general, if it's possible to derive the <code>Debug</code>, there are no reasons against doing it.</p> +</li> +</ul> +<h3 id="when-is-it-possible-to-derive-a-trait">When is it possible to derive a trait?</h3> +<p>When all fields of a struct/variants of an enum implement that trait.</p> +<h3 id="should-all-traits-always-be-derived-if-it-is-possible">Should all traits always be derived if it is possible?</h3> +<p>No. Although it may be tempting to just slap <code>#[derive(Clone, Copy)]</code> everywhere, it would be counter-effective. For example, at some later point you might add a non-Copy field to the struct and your (or, what's worse, someone else's!) code would break. Another example: it makes little sense to use containers as keys in hashmaps or to compare tweets.</p> +<h1 id="generics">Generics</h1> +<p>Suppose we want to find the largest element in a sequence and return it. Very much on purpose, we didn't specify what type these elements would be - ideally, we would love it to work on all types that have a defined notion of a <em>largest</em> element. However, to make things simpler for now, let's focus only on two primitive types: <code>i32</code> and <code>char</code>. Let's try to write the code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest_i32</span><span>(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">i32</span><span>]) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest_char</span><span>(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">char</span><span>]) -&gt; </span><span style="color:#8959a8;">char </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> number_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">34</span><span>, </span><span style="color:#f5871f;">50</span><span>, </span><span style="color:#f5871f;">25</span><span>, </span><span style="color:#f5871f;">100</span><span>, </span><span style="color:#f5871f;">65</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest_i32</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>number_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest number is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> char_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#718c00;">&#39;y&#39;</span><span>, </span><span style="color:#718c00;">&#39;m&#39;</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>, </span><span style="color:#718c00;">&#39;q&#39;</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest_char</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>char_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest char is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/non_generic.rs">non_generic.rs</a>)</sub></p> +<p>Perfect, it works! Now only twenty more types to go...</p> +<p>Fortunately, Rust gives us a way to avoid all this code duplication and generalize the types we're working on.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span></code></pre> +<p>Cleaner already - we merged possibly very many implementations into one. But, when we try to compile this:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0369]: binary operation `&gt;` cannot be applied to type `T` +</span><span> --&gt; src/main.rs:5:17 +</span><span> | +</span><span>5 | if item &gt; largest { +</span><span> | ---- ^ ------- T +</span><span> | | +</span><span> | T +</span><span> | +</span><span>help: consider restricting type parameter `T` +</span><span> | +</span><span>1 | fn largest&lt;T: std::cmp::PartialOrd&gt;(list: &amp;[T]) -&gt; T { +</span><span> | ++++++++++++++++++++++ +</span></code></pre> +<p>Since <code>T</code> can be of absolutely any type now, the compiler cannot be sure that operator <code>&gt;</code> is defined. This aligns with what we wanted, as without comparing elements we don't have a notion of the largest one either. As always, the compiler comes to our aid:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd</span><span>&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span></code></pre> +<p>We call this a <em>trait bound</em>, a way to provide constraints on what kind of types we are talking about in a given context. This implementation almost works now. Let's look at the new error.</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0508]: cannot move out of type `[T]`, a non-copy slice +</span><span> --&gt; src/main.rs:2:23 +</span><span> | +</span><span>2 | let mut largest = list[0]; +</span><span> | ^^^^^^^ +</span><span> | | +</span><span> | cannot move out of here +</span><span> | move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait +</span><span> | help: consider borrowing here: `&amp;list[0]` +</span><span> +</span><span>error[E0507]: cannot move out of a shared reference +</span><span> --&gt; src/main.rs:4:18 +</span><span> | +</span><span>4 | for &amp;item in list { +</span><span> | ----- ^^^^ +</span><span> | || +</span><span> | |data moved here +</span><span> | |move occurs because `item` has type `T`, which does not implement the `Copy` trait +</span><span> | help: consider removing the `&amp;`: `item` +</span></code></pre> +<p>Our function attempts to take ownership, but, again, the compiler doesn't know whether <code>T</code> can just be trivially copied. Rust allows us to combine multiple trait bounds together:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd </span><span style="color:#3e999f;">+ </span><span style="color:#c99e00;">Copy</span><span>&gt;(</span><span style="color:#f5871f;">list</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[T]) -&gt; T { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> largest </span><span style="color:#3e999f;">=</span><span> list[</span><span style="color:#f5871f;">0</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">for </span><span style="color:#3e999f;">&amp;</span><span>item </span><span style="color:#3e999f;">in</span><span> list { +</span><span> </span><span style="color:#8959a8;">if</span><span> item </span><span style="color:#3e999f;">&gt;</span><span> largest { +</span><span> largest </span><span style="color:#3e999f;">=</span><span> item; +</span><span> } +</span><span> } +</span><span> +</span><span> largest +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> number_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">34</span><span>, </span><span style="color:#f5871f;">50</span><span>, </span><span style="color:#f5871f;">25</span><span>, </span><span style="color:#f5871f;">100</span><span>, </span><span style="color:#f5871f;">65</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>number_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest number is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> char_list </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#718c00;">&#39;y&#39;</span><span>, </span><span style="color:#718c00;">&#39;m&#39;</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>, </span><span style="color:#718c00;">&#39;q&#39;</span><span>]; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>char_list); +</span><span> println!(</span><span style="color:#718c00;">&quot;The largest char is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/generic_largest.rs">generic_largest.rs</a>)</sub></p> +<h2 id="a-powerful-tool">A powerful tool</h2> +<p>There's a lot more that we can do with generics:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fmt::Debug; +</span><span> +</span><span style="color:#999999;">// generic enums +</span><span style="color:#8959a8;">enum </span><span>OurOption&lt;T&gt; { +</span><span> </span><span style="color:#c99e00;">Some</span><span>(T), +</span><span> </span><span style="color:#c99e00;">None</span><span>, +</span><span>} +</span><span> +</span><span style="color:#999999;">// generic structs +</span><span style="color:#8959a8;">struct </span><span>Tuple2&lt;T, U&gt; { +</span><span> </span><span style="color:#c82829;">x</span><span>: T, +</span><span> </span><span style="color:#c82829;">y</span><span>: U, +</span><span>} +</span><span> +</span><span style="color:#999999;">// generic implementation +</span><span style="color:#8959a8;">impl</span><span>&lt;T, U&gt; Tuple2&lt;T, U&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">x</span><span>: T, </span><span style="color:#f5871f;">y</span><span>: U) -&gt; </span><span style="color:#8959a8;">Self </span><span>{ +</span><span> </span><span style="color:#8959a8;">Self </span><span>{ x, y } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Pair&lt;T&gt; { +</span><span> </span><span style="color:#c82829;">x</span><span>: T, +</span><span> </span><span style="color:#c82829;">y</span><span>: T, +</span><span>} +</span><span> +</span><span style="color:#999999;">// conditional implementation +</span><span style="color:#8959a8;">impl</span><span>&lt;T: </span><span style="color:#c99e00;">PartialOrd </span><span style="color:#3e999f;">+ </span><span style="color:#c99e00;">Copy</span><span>&gt; Pair&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">largest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; T { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.x </span><span style="color:#3e999f;">&gt; </span><span style="color:#c82829;">self</span><span>.y { +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.y +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// alternative syntax +</span><span style="color:#8959a8;">impl</span><span>&lt;T&gt; Pair&lt;T&gt; +</span><span style="color:#8959a8;">where +</span><span> T: PartialOrd + Copy, +</span><span>{ +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">smallest</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; T { +</span><span> </span><span style="color:#8959a8;">if </span><span style="color:#c82829;">self</span><span>.x </span><span style="color:#3e999f;">&lt; </span><span style="color:#c82829;">self</span><span>.y { +</span><span> </span><span style="color:#c82829;">self</span><span>.x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c82829;">self</span><span>.y +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// Here information about the concrete underlying type is erased +</span><span style="color:#999999;">// We can only either format or clone the result +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">cloning_machine</span><span>(</span><span style="color:#f5871f;">item</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>(</span><span style="color:#f5871f;">impl Clone</span><span> + </span><span style="color:#f5871f;">Debug</span><span>)) -&gt; impl Clone </span><span style="color:#3e999f;">+</span><span> Debug { +</span><span> item.</span><span style="color:#4271ae;">clone</span><span>() +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> _opt </span><span style="color:#3e999f;">= </span><span>OurOption::Some(</span><span style="color:#f5871f;">10</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> _p1 </span><span style="color:#3e999f;">=</span><span> Tuple2 { x: </span><span style="color:#f5871f;">5</span><span>, y: </span><span style="color:#f5871f;">10 </span><span>}; +</span><span> </span><span style="color:#8959a8;">let</span><span> _p2 </span><span style="color:#3e999f;">= </span><span>Tuple2::new(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2.5</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> arr </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>]; +</span><span> </span><span style="color:#8959a8;">let</span><span> arr2 </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">cloning_machine</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>arr); +</span><span> </span><span style="color:#999999;">// arr2[0]; // won&#39;t compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, arr2) +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/generics.rs">generics.rs</a>)</sub></p> +<p>A bit more involved example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">use </span><span>std::fmt::{Display, Formatter}; +</span><span> +</span><span style="color:#8959a8;">trait </span><span>DefaultishablyPrintable&lt;T&gt; { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">defaultish_print</span><span>() +</span><span> </span><span style="color:#8959a8;">where +</span><span> T: Display + Default, +</span><span> { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, T::default()) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Foo; +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Bar; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Display </span><span style="color:#8959a8;">for </span><span>Bar { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">fmt</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">f</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span>Formatter&lt;&#39;</span><span style="color:#3e999f;">_</span><span>&gt;) -&gt; std::fmt::Result { +</span><span> f.</span><span style="color:#4271ae;">write_str</span><span>(</span><span style="color:#718c00;">&quot;this is a bar&quot;</span><span>) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Default </span><span style="color:#8959a8;">for </span><span>Bar { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">default</span><span>() -&gt; </span><span style="color:#8959a8;">Self </span><span>{ +</span><span> Bar </span><span style="color:#999999;">// well, we have no other choice +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>DefaultishablyPrintable&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#8959a8;">for </span><span>Foo {} +</span><span> +</span><span style="color:#8959a8;">impl </span><span>DefaultishablyPrintable&lt;Bar&gt; </span><span style="color:#8959a8;">for </span><span>Foo {} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#3e999f;">&lt;</span><span>Foo </span><span style="color:#3e999f;">as </span><span>DefaultishablyPrintable&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;</span><span style="color:#3e999f;">&gt;</span><span>::defaultish_print(); +</span><span> &lt;Foo </span><span style="color:#3e999f;">as </span><span>DefaultishablyPrintable&lt;Bar&gt;&gt;::defaultish_print(); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/generics_fun.rs">generics_fun.rs</a>)</sub></p> +<h2 id="static-vs-dynamic-dispatch">Static vs dynamic dispatch</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">trait </span><span>Speak { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str</span><span>; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Dog; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Speak </span><span style="color:#8959a8;">for </span><span>Dog { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;Hau hau&quot; </span><span style="color:#999999;">// it&#39;s a Polish dog! +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">struct </span><span>Human; +</span><span> +</span><span style="color:#8959a8;">impl </span><span>Speak </span><span style="color:#8959a8;">for </span><span>Human { +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">speak</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;Hello world&quot; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// It works like templates in C++ +</span><span style="color:#999999;">// A different function will be generated for each T during compilation +</span><span style="color:#999999;">// This process is called &quot;monomorphization&quot; +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">static_dispatch</span><span>&lt;T: Speak&gt;(</span><span style="color:#f5871f;">speaking</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>T) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, speaking.</span><span style="color:#4271ae;">speak</span><span>()); +</span><span>} +</span><span> +</span><span style="color:#999999;">// Only one copy of that function will exist in the compiled binary +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#f5871f;">speaking</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>dyn Speak) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, speaking.</span><span style="color:#4271ae;">speak</span><span>()); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> dog </span><span style="color:#3e999f;">=</span><span> Dog; +</span><span> </span><span style="color:#8959a8;">let</span><span> human </span><span style="color:#3e999f;">=</span><span> Human; +</span><span> +</span><span> </span><span style="color:#4271ae;">static_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>dog); +</span><span> </span><span style="color:#4271ae;">static_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>human); +</span><span> +</span><span> </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>dog); +</span><span> </span><span style="color:#4271ae;">dynamic_dispatch</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>human); +</span><span> +</span><span> </span><span style="color:#999999;">// The observable behavior is identical +</span><span> </span><span style="color:#999999;">// Static dispatch in general is a bit faster, +</span><span> </span><span style="color:#999999;">// because there is no need to perform a &quot;vtable lookup&quot;. +</span><span> </span><span style="color:#999999;">// But it can also result in bigger binary sizes. +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/static_dynamic_dispatch.rs">static_dynamic_dispatch.rs</a>)</sub></p> +<h1 id="lifetimes">Lifetimes</h1> +<p>Going back to the lesson about ownership, if we try to compile the following code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> r; +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; +</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; +</span><span> } +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); +</span><span>} +</span></code></pre> +<p>we should expect to get an error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0597]: `x` does not live long enough +</span><span> --&gt; src/main.rs:7:17 +</span><span> | +</span><span>7 | r = &amp;x; +</span><span> | ^^ borrowed value does not live long enough +</span><span>8 | } +</span><span> | - `x` dropped here while still borrowed +</span><span>9 | +</span><span>10 | println!(&quot;r: {}&quot;, r); +</span><span> | - borrow later used here +</span></code></pre> +<p>Courtesy of the borrow checker, we didn't end up with a dangling reference. But what exactly is happening behind the scenes? Rust introduces a concept of annotated lifetimes, where the lifetime of each value is being marked and tracked by the checker. Let's look at some examples:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> r; </span><span style="color:#999999;">// ---------+-- &#39;a +</span><span> </span><span style="color:#999999;">// | +</span><span> { </span><span style="color:#999999;">// | +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// -+-- &#39;b | +</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; </span><span style="color:#999999;">// | | +</span><span> } </span><span style="color:#999999;">// -+ | +</span><span> </span><span style="color:#999999;">// | +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); </span><span style="color:#999999;">// | +</span><span>} </span><span style="color:#999999;">// ---------+ +</span></code></pre> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// ----------+-- &#39;b +</span><span> </span><span style="color:#999999;">// | +</span><span> </span><span style="color:#8959a8;">let</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>x; </span><span style="color:#999999;">// --+-- &#39;a | +</span><span> </span><span style="color:#999999;">// | | +</span><span> println!(</span><span style="color:#718c00;">&quot;r: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, r); </span><span style="color:#999999;">// | | +</span><span> </span><span style="color:#999999;">// --+ | +</span><span>} </span><span style="color:#999999;">// ----------+ +</span></code></pre> +<h2 id="annotations">Annotations</h2> +<p>Let's consider the following code finding the longer out of two strings:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>, </span><span style="color:#f5871f;">y</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> y.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> y +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> string1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;abcd&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> string2 </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;xyz&quot;</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">longest</span><span>(string1.</span><span style="color:#4271ae;">as_str</span><span>(), string2); +</span><span> println!(</span><span style="color:#718c00;">&quot;The longest string is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span>} +</span></code></pre> +<p>If we try to compile this, we will get an error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0106]: missing lifetime specifier +</span><span> --&gt; src/main.rs:9:33 +</span><span> | +</span><span>9 | fn longest(x: &amp;str, y: &amp;str) -&gt; &amp;str { +</span><span> | ---- ---- ^ expected named lifetime parameter +</span><span> | +</span><span> = help: this function&#39;s return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +</span><span>help: consider introducing a named lifetime parameter +</span><span> | +</span><span>9 | fn longest&lt;&#39;a&gt;(x: &amp;&#39;a str, y: &amp;&#39;a str) -&gt; &amp;&#39;a str { +</span><span> | ++++ ++ ++ ++ +</span></code></pre> +<p>This is because Rust doesn't know which of the two provided strings (<code>x</code> or <code>y</code>) will be returned from the function. And because they potentially have different lifetimes, the lifetime of what we are returning remains unclear to the compiler - it needs our help.</p> +<p>Rust provides syntax for specifying lifetimes. The lifetime parameter name from the example (<code>a</code>) doesn't have any concrete meaning - it's just an arbitrary name for this one lifetime.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">i32 </span><span style="color:#999999;">// a reference +</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a i32 </span><span style="color:#999999;">// a reference with an explicit lifetime +</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a mut i32 </span><span style="color:#999999;">// a mutable reference with an explicit lifetime +</span></code></pre> +<p>So, knowing this, let's address the compiler's demands.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>, </span><span style="color:#f5871f;">y</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> x.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> y.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> x +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> y +</span><span> } +</span><span>} +</span></code></pre> +<p>When working with lifetimes, our work will usually revolve around specifying relationships between lifetimes of different values so that the compiler can successfully reason about the program's safety. In the context of the example above, this signature means that both of the function's arguments and its output will live at least as long as lifetime <code>'a</code>. In practice, this means that the output's lifetime will be equal to the smaller of the two inputs' lifetimes.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">longest</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">first</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>, </span><span style="color:#f5871f;">second</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str</span><span>) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a str </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> first.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&gt;</span><span> second.</span><span style="color:#4271ae;">len</span><span>() { +</span><span> first +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> second +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> string1 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;long string is long&quot;</span><span>); +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> string2 </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;xyz&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> result </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">longest</span><span>(string1.</span><span style="color:#4271ae;">as_str</span><span>(), string2.</span><span style="color:#4271ae;">as_str</span><span>()); +</span><span> println!(</span><span style="color:#718c00;">&quot;The longest string is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, result); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// This doesn&#39;t compile - incorrect lifetimes +</span><span> </span><span style="color:#999999;">// +</span><span> </span><span style="color:#999999;">// let string1 = String::from(&quot;long string is long&quot;); +</span><span> </span><span style="color:#999999;">// let result; +</span><span> </span><span style="color:#999999;">// { +</span><span> </span><span style="color:#999999;">// let string2 = String::from(&quot;xyz&quot;); +</span><span> </span><span style="color:#999999;">// result = longest(string1.as_str(), string2.as_str()); +</span><span> </span><span style="color:#999999;">// } +</span><span> </span><span style="color:#999999;">// println!(&quot;The longest string is {}&quot;, result); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/lifetimes_basic.rs">lifetimes_basic.rs</a>)</sub></p> +<p>Trying to compile the second variant displeases the compiler (just like we hoped).</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0597]: `string2` does not live long enough +</span><span> --&gt; src/main.rs:6:44 +</span><span> | +</span><span>6 | result = longest(string1.as_str(), string2.as_str()); +</span><span> | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough +</span><span>7 | } +</span><span> | - `string2` dropped here while still borrowed +</span><span>8 | println!(&quot;The longest string is {}&quot;, result); +</span><span> | ------ borrow later used here +</span></code></pre> +<h2 id="lifetime-elision">Lifetime elision</h2> +<p>We now know how to explicitly write lifetime parameters, but you might recall that we don't always have to that. Indeed, Rust will first try to figure out the lifetimes itself, applying a set of predefined rules. We call this <em>lifetime elision</em>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span><span> </span><span style="color:#8959a8;">if</span><span> seq.</span><span style="color:#4271ae;">len</span><span>() </span><span style="color:#3e999f;">&lt; </span><span style="color:#f5871f;">2 </span><span>{ +</span><span> seq +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>seq[</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">2</span><span>] +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> seq </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>]; +</span><span> +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;First two elements of the sequence: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, +</span><span> </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>seq[</span><span style="color:#3e999f;">..</span><span>]) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/06-types-reasoning/lifetimes_elision.rs">lifetimes_elision.rs</a>)</sub></p> +<p>The above works, even though we didn't specify any lifetime parameters at all. The reason lies in the rules we mentioned, which are as follows (where input lifetimes are lifetimes on parameters and output lifetimes are lifetimes on return values):</p> +<ul> +<li> +<p>Each parameter that is a reference gets its own lifetime parameter.</p> +</li> +<li> +<p>If there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters.</p> +</li> +<li> +<p>If there are multiple input lifetime parameters, but one of them is <code>&amp;self</code> or <code>&amp;mut self</code>, the lifetime of <code>self</code> is assigned to all output lifetime parameters.</p> +</li> +</ul> +<p>Let's try to understand how the compiler inferred the lifetimes of our <code>first_two</code> functions. We start with the following signature:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>Then, we apply the first rule:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> [</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>Next, we check the second rule. It applies here as well.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_two</span><span>&lt;</span><span style="color:#8959a8;">&#39;a</span><span>&gt;(</span><span style="color:#f5871f;">seq</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a</span><span> [</span><span style="color:#8959a8;">u32</span><span>]) -&gt; </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;a </span><span>[</span><span style="color:#8959a8;">u32</span><span>] { +</span></code></pre> +<p>With that, we arrive at a state where all lifetimes are specified.</p> +<h2 id="static-lifetime">Static lifetime</h2> +<p>There exists one special lifetime called <code>'static</code>, which means that a reference can live for the entire duration of the program. All string literals are annotated with this lifetime as they are stored directly in the program's binary. Full type annotation of a string literal in Rust is therefore as follows:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;I have a static lifetime.&quot;</span><span>; +</span></code></pre> +<h1 id="obligatory-reading">Obligatory reading</h1> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/book/ch10-00-generics.html">The Book, chapter 10</a></p> +</li> +<li> +<p><a href="https://oswalt.dev/2021/06/polymorphism-in-rust/">Polymorphism in Rust</a></p> +</li> +</ul> + + + + + Enums + 2022-03-13T00:00:00+00:00 + 2022-03-13T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/ + + <h2 id="enums">Enums</h2> +<p>It is often the case that we want to define a variable that can only take +a certain set of values and the values are known up front. In C you can an <code>enum</code> for this.</p> +<pre data-lang="c" style="background-color:#ffffff;color:#4d4d4c;" class="language-c "><code class="language-c" data-lang="c"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;stdio.h&gt; +</span><span> +</span><span style="color:#8959a8;">enum </span><span>shirt_size { +</span><span> small, +</span><span> medium, +</span><span> large, +</span><span> xlarge +</span><span>}; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_size</span><span>(</span><span style="color:#8959a8;">enum</span><span> shirt_size </span><span style="color:#f5871f;">size</span><span>) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;my size is &quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> </span><span style="color:#8959a8;">if </span><span>(size </span><span style="color:#3e999f;">==</span><span> small) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;small&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> } </span><span style="color:#8959a8;">else if </span><span>(size </span><span style="color:#3e999f;">==</span><span> medium) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;medium&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> } </span><span style="color:#8959a8;">else if </span><span>(size </span><span style="color:#3e999f;">==</span><span> large) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;large&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> } </span><span style="color:#8959a8;">else if </span><span>(size </span><span style="color:#3e999f;">==</span><span> xlarge) { +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;xlarge&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;unknown&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span> } +</span><span> </span><span style="color:#4271ae;">printf(</span><span style="color:#718c00;">&quot;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&quot;</span><span style="color:#4271ae;">)</span><span>; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">enum</span><span> shirt_size my_size </span><span style="color:#3e999f;">=</span><span> medium; +</span><span> </span><span style="color:#c82829;">print_size</span><span style="color:#4271ae;">(my_size)</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/enums.c">enums.c</a>)</sub></p> +<p>However, in C enums are just integers. Nothing prevents us from writing</p> +<pre data-lang="c" style="background-color:#ffffff;color:#4d4d4c;" class="language-c "><code class="language-c" data-lang="c"><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">enum</span><span> shirt_size my_size </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">666</span><span>; +</span><span> </span><span style="color:#c82829;">print_size</span><span style="color:#4271ae;">(my_size)</span><span>; +</span><span>} +</span></code></pre> +<p>C++ introduces enum classes which are type-safe. Legacy enums are also somewhat safer than in C (same code as above):</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>&lt;source&gt;:27:31: error: invalid conversion from &#39;int&#39; to &#39;shirt_size&#39; [-fpermissive] +</span><span> 27 | enum shirt_size my_size = 666; +</span><span> | ^~~ +</span><span> | | +</span><span> | int +</span></code></pre> +<p>Some programming languages (especially functional ones) allow programmers to define +enums which carry additional information. Such types are usually called <code>tagged unions</code> +or <code>algebraic data types</code>.</p> +<p>In C++ we can use <code>union</code> with an <code>enum</code> tag to define it:</p> +<pre data-lang="cpp" style="background-color:#ffffff;color:#4d4d4c;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#8959a8;">#include </span><span style="color:#718c00;">&lt;iostream&gt; +</span><span> +</span><span style="color:#999999;">// Taken from: https://en.cppreference.com/w/cpp/language/union +</span><span> +</span><span style="color:#999999;">// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), +</span><span style="color:#999999;">// and three variant members (c, i, d) +</span><span style="color:#8959a8;">struct </span><span>S +</span><span>{ +</span><span> </span><span style="color:#8959a8;">enum</span><span>{</span><span style="color:#c99e00;">CHAR</span><span>, </span><span style="color:#c99e00;">INT</span><span>, DOUBLE} tag; +</span><span> </span><span style="color:#8959a8;">union +</span><span> { +</span><span> </span><span style="color:#8959a8;">char</span><span> c; +</span><span> </span><span style="color:#8959a8;">int</span><span> i; +</span><span> </span><span style="color:#8959a8;">double</span><span> d; +</span><span> }; +</span><span>}; +</span><span> +</span><span style="color:#8959a8;">void </span><span style="color:#4271ae;">print_s</span><span>(</span><span style="color:#8959a8;">const</span><span> S</span><span style="color:#3e999f;">&amp; </span><span style="color:#f5871f;">s</span><span>) +</span><span>{ +</span><span> </span><span style="color:#8959a8;">switch</span><span>(s.</span><span style="color:#c82829;">tag</span><span>) +</span><span> { +</span><span> </span><span style="color:#8959a8;">case</span><span> S::</span><span style="color:#c99e00;">CHAR</span><span>: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">c </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> S::</span><span style="color:#c99e00;">INT</span><span>: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">i </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> </span><span style="color:#8959a8;">case</span><span> S::DOUBLE: std::cout </span><span style="color:#3e999f;">&lt;&lt;</span><span> s.</span><span style="color:#c82829;">d </span><span style="color:#3e999f;">&lt;&lt; </span><span style="color:#718c00;">&#39;</span><span style="color:#f5871f;">\n</span><span style="color:#718c00;">&#39;</span><span>; </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">int </span><span style="color:#4271ae;">main</span><span>() +</span><span>{ +</span><span> S s </span><span style="color:#3e999f;">= </span><span>{S::</span><span style="color:#c99e00;">CHAR</span><span>, </span><span style="color:#718c00;">&#39;a&#39;</span><span>}; +</span><span> </span><span style="color:#c82829;">print_s</span><span style="color:#4271ae;">(s)</span><span>; +</span><span> s.</span><span style="color:#c82829;">tag </span><span style="color:#3e999f;">=</span><span> S::</span><span style="color:#c99e00;">INT</span><span>; +</span><span> s.</span><span style="color:#c82829;">i </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">123</span><span>; +</span><span> </span><span style="color:#c82829;">print_s</span><span style="color:#4271ae;">(s)</span><span>; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/tagged_union.cpp">tagged_union.cpp</a>)</sub></p> +<p>C++17 introduced a new feature called <code>variant</code> which generalizes this concept. +You can read more about it <a href="https://en.cppreference.com/w/cpp/utility/variant">here</a>.</p> +<p>Java has a more or less analogous feature called <code>sealed classes</code> +since <a href="https://docs.oracle.com/en/java/javase/17/language/sealed-classes-and-interfaces.html.">version 17</a>.</p> +<h2 id="enums-in-rust">Enums in Rust</h2> +<p>Let's see how they are defined in Rust.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span style="color:#8959a8;">enum </span><span>NamedSize { +</span><span> Small, +</span><span> Medium, +</span><span> Large, +</span><span> </span><span style="color:#666969;">XL</span><span>, +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span style="color:#8959a8;">enum </span><span>ShirtSize { +</span><span> Named(NamedSize), +</span><span> Numeric(</span><span style="color:#8959a8;">u32</span><span>), +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Isn&#39;t it strange that some clothes&#39; sizes are adjectives like </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">,&quot;</span><span>, +</span><span> ShirtSize::Named(NamedSize::Small) +</span><span> ); +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;but sometimes they are numbers like </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">?&quot;</span><span>, +</span><span> ShirtSize::Numeric(</span><span style="color:#f5871f;">42</span><span>) +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/enums.rs">enums.rs</a>)</sub></p> +<p>In Rust, enums are a core feature of the language. +You may have heard that one of Rust's defining characteristics is +the absence of <a href="https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions">&quot;the billion dollar mistake&quot;</a>. +So what can we do to say that a value is missing if there is no <code>null</code>?</p> +<p>In Rust, we can use the <code>Option</code> type to represent the absence of a value.</p> +<p>Option is defined as:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">enum </span><span>Option&lt;T&gt; { +</span><span> </span><span style="color:#c99e00;">Some</span><span>(T), +</span><span> </span><span style="color:#c99e00;">None</span><span>, +</span><span>} +</span></code></pre> +<p>The <code>&lt;T&gt;</code> part is called the &quot;type parameter&quot; and it causes Option to be generic. +We won't go deeper into this for now.</p> +<p>The fact that variables which could be <code>null</code> in other languages have a different type in Rust is +the solution to the billion dollar mistake!</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> not_null: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> not_null </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">43</span><span>; +</span><span> </span><span style="color:#999999;">// not_null = None; // this won&#39;t compile because it&#39;s a different type! +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> nullable: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">43</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// such construction is rare, but possible +</span><span> </span><span style="color:#8959a8;">let mut</span><span> double_nullable: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> </span><span style="color:#999999;">// assert_ne!(double_nullable, Some(42)); // this won&#39;t even compile because it&#39;s a different type! +</span><span> double_nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> double_nullable </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// None and Some(None) are different! +</span><span> assert_ne!(double_nullable, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// Now recall that division by 0 *panics* +</span><span> </span><span style="color:#999999;">// A panic is an unrecoverable error +</span><span> </span><span style="color:#999999;">// It is not an exception! +</span><span> </span><span style="color:#999999;">// And in Rust there are no exceptions, so there are no try/catch blocks +</span><span> </span><span style="color:#999999;">// Now let&#39;s imagine that we want to divide one number by another +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">divide</span><span>(</span><span style="color:#f5871f;">dividend</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">divisor</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> dividend </span><span style="color:#3e999f;">/</span><span> divisor +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We get the divisor from the user, so it can be 0 +</span><span> </span><span style="color:#999999;">// We want to handle this situation gracefully - we don&#39;t want to crash the program! +</span><span> </span><span style="color:#999999;">// We can do this by using the Option&lt;T&gt; type +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">safe_divide</span><span>(</span><span style="color:#f5871f;">dividend</span><span>: </span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#f5871f;">divisor</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">if</span><span> divisor </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#c99e00;">None +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#c99e00;">Some</span><span>(dividend </span><span style="color:#3e999f;">/</span><span> divisor) +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Fortunately, such a function is already included in the standard library +</span><span> </span><span style="color:#8959a8;">let</span><span> number: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> </span><span style="color:#999999;">// We need to specify the type explicitly +</span><span> </span><span style="color:#999999;">// because checked_div is implemented for all integer types +</span><span> </span><span style="color:#999999;">// and Rust won&#39;t know which type we want to use +</span><span> assert_eq!(number.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">2</span><span>), </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">21</span><span>)); +</span><span> assert_eq!(number.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">0</span><span>), </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// Now let&#39;s imagine we search for a value in a vector +</span><span> </span><span style="color:#8959a8;">let</span><span> numbers </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#f5871f;">4</span><span>, </span><span style="color:#f5871f;">5</span><span>]; +</span><span> </span><span style="color:#8959a8;">let</span><span> three </span><span style="color:#3e999f;">=</span><span> numbers.</span><span style="color:#4271ae;">iter</span><span>().</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">find</span><span>(|</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">3</span><span>); +</span><span> assert_eq!(three, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> </span><span style="color:#8959a8;">let</span><span> seven </span><span style="color:#3e999f;">=</span><span> numbers.</span><span style="color:#4271ae;">iter</span><span>().</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">find</span><span>(|</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">7</span><span>); +</span><span> assert_eq!(seven, </span><span style="color:#c99e00;">None</span><span>); +</span><span> </span><span style="color:#999999;">// We won&#39;t delve deeper into the details of how iterators work for now, +</span><span> </span><span style="color:#999999;">// but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust +</span><span> +</span><span> </span><span style="color:#999999;">// Usually there are two kinds of methods: +</span><span> </span><span style="color:#999999;">// ones that will panic if the argument is incorrect, +</span><span> </span><span style="color:#999999;">// numbers[8]; // this will panic! +</span><span> </span><span style="color:#999999;">// and `checked` ones that return an Option +</span><span> assert_eq!(numbers.</span><span style="color:#4271ae;">get</span><span>(</span><span style="color:#f5871f;">8</span><span>), </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// We can use `unwrap` to get the value out of an Option +</span><span> </span><span style="color:#999999;">// but we must be absolutely sure that the Option is Some, otherwise we&#39;ll get a panic +</span><span> </span><span style="color:#999999;">// numbers.get(8).unwrap(); // this will panic! +</span><span> assert_eq!(numbers.</span><span style="color:#4271ae;">get</span><span>(</span><span style="color:#f5871f;">8</span><span>).</span><span style="color:#4271ae;">copied</span><span>().</span><span style="color:#4271ae;">unwrap_or</span><span>(</span><span style="color:#f5871f;">0</span><span>), </span><span style="color:#f5871f;">0</span><span>); </span><span style="color:#999999;">// or we can provide a default value +</span><span> +</span><span> </span><span style="color:#999999;">// Usually instead of unwrapping we use pattern matching, we&#39;ll get to this in a minute +</span><span> </span><span style="color:#999999;">// but first let&#39;s see what else we can do with an option +</span><span> </span><span style="color:#8959a8;">let</span><span> number: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>); +</span><span> </span><span style="color:#999999;">// We can use `map` to transform the value inside an Option +</span><span> </span><span style="color:#8959a8;">let</span><span> doubled </span><span style="color:#3e999f;">=</span><span> number.</span><span style="color:#4271ae;">map</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x </span><span style="color:#3e999f;">* </span><span style="color:#f5871f;">2</span><span>); +</span><span> assert_eq!(doubled, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">84</span><span>)); +</span><span> </span><span style="color:#999999;">// We can use flatten to reduce one level of nesting +</span><span> </span><span style="color:#8959a8;">let</span><span> nested </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> assert_eq!(nested.</span><span style="color:#4271ae;">flatten</span><span>(), </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">42</span><span>)); +</span><span> </span><span style="color:#999999;">// We can use `and_then` to chain multiple options +</span><span> </span><span style="color:#999999;">// This operation is called `flatmap` in some languages +</span><span> </span><span style="color:#8959a8;">let</span><span> chained </span><span style="color:#3e999f;">=</span><span> number +</span><span> .</span><span style="color:#4271ae;">and_then</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">0</span><span>)) +</span><span> .</span><span style="color:#4271ae;">and_then</span><span>(|</span><span style="color:#f5871f;">x</span><span>| x.</span><span style="color:#4271ae;">checked_div</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> assert_eq!(chained, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#999999;">// The last two things we&#39;ll cover here are `take` and `replace` +</span><span> </span><span style="color:#999999;">// They are important when dealing with non-Copy types +</span><span> </span><span style="color:#999999;">// `take` will return the value inside an Option and leave a None in its place +</span><span> </span><span style="color:#8959a8;">let mut</span><span> option: </span><span style="color:#c99e00;">Option</span><span>&lt;</span><span style="color:#8959a8;">i32</span><span>&gt; </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> </span><span style="color:#999999;">// Again, we need to specify the type +</span><span> </span><span style="color:#999999;">// Even though we want to say that there is no value inside the Option, +</span><span> </span><span style="color:#999999;">// this absent value must have a concrete type! +</span><span> assert_eq!(option.</span><span style="color:#4271ae;">take</span><span>(), </span><span style="color:#c99e00;">None</span><span>); +</span><span> assert_eq!(option, </span><span style="color:#c99e00;">None</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> y </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">take</span><span>(); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">None</span><span>); +</span><span> assert_eq!(y, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> +</span><span> </span><span style="color:#999999;">// `replace` can be used to swap the value inside an Option +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> old </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#f5871f;">5</span><span>); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">5</span><span>)); +</span><span> assert_eq!(old, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">2</span><span>)); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">None</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> old </span><span style="color:#3e999f;">=</span><span> x.</span><span style="color:#4271ae;">replace</span><span>(</span><span style="color:#f5871f;">3</span><span>); +</span><span> assert_eq!(x, </span><span style="color:#c99e00;">Some</span><span>(</span><span style="color:#f5871f;">3</span><span>)); +</span><span> assert_eq!(old, </span><span style="color:#c99e00;">None</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/option.rs">option.rs</a>)</sub></p> +<h2 id="pattern-matching">Pattern matching</h2> +<p>Pattern matching is a powerful feature of Rust and many functional languages, but it's slowly making +its way into imperative languages like Java and Python as well.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// Pattern matching is basically a switch on steroids. +</span><span> </span><span style="color:#8959a8;">let</span><span> number </span><span style="color:#3e999f;">= </span><span>rand::random::&lt;</span><span style="color:#8959a8;">i32</span><span>&gt;(); +</span><span> </span><span style="color:#8959a8;">match</span><span> number </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">7 </span><span>{ +</span><span> </span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is divisible by 7&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is *almost* divisible by 7&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{number}</span><span style="color:#718c00;"> is not divisible by 7&quot;</span><span>), +</span><span> } +</span><span> +</span><span> #[</span><span style="color:#c82829;">derive</span><span>(Debug)] +</span><span> </span><span style="color:#8959a8;">enum </span><span>Color { +</span><span> Pink, +</span><span> Brown, +</span><span> Lime, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> color </span><span style="color:#3e999f;">= </span><span>Color::Lime; +</span><span> </span><span style="color:#8959a8;">match</span><span> color { +</span><span> Color::Pink </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not my favorite color!&quot;</span><span>), </span><span style="color:#999999;">// _ is a wildcard +</span><span> </span><span style="color:#999999;">// Rust will statically check that we covered all cases or included a default case. +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can also use pattern matching to match on multiple values. +</span><span> </span><span style="color:#8959a8;">match </span><span>(color, number </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">7</span><span>) { +</span><span> (Color::Pink, </span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color and number!&quot;</span><span>), +</span><span> (Color::Pink, </span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite color!&quot;</span><span>), +</span><span> (</span><span style="color:#3e999f;">_</span><span>, </span><span style="color:#f5871f;">0</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;My favorite number!&quot;</span><span>), +</span><span> (</span><span style="color:#3e999f;">_</span><span>, </span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not my favorite color or number!&quot;</span><span>), +</span><span> } +</span><span> </span><span style="color:#999999;">// (This is not special syntax, we&#39;re just pattern matching tuples.) +</span><span> +</span><span> </span><span style="color:#999999;">// But we can also *destructure* the value +</span><span> </span><span style="color:#8959a8;">struct </span><span>Human { +</span><span> </span><span style="color:#c82829;">age</span><span>: </span><span style="color:#8959a8;">u8</span><span>, +</span><span> </span><span style="color:#c82829;">favorite_color</span><span>: Color, +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> john </span><span style="color:#3e999f;">=</span><span> Human { +</span><span> age: </span><span style="color:#f5871f;">42</span><span>, +</span><span> favorite_color: Color::Pink, +</span><span> }; +</span><span> +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#3e999f;">&amp;</span><span>john { +</span><span> Human { +</span><span> age: </span><span style="color:#f5871f;">42</span><span>, +</span><span> favorite_color: Color::Pink, +</span><span> } </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Okay, that&#39;s John!&quot;</span><span>), +</span><span> Human { +</span><span> favorite_color: Color::Pink, +</span><span> </span><span style="color:#3e999f;">.. +</span><span> } </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Not John, but still his favorite color!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Somebody else?&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Note two things: +</span><span> </span><span style="color:#999999;">// 1. Color is *not* Eq, so we can&#39;t use == to compare it, but pattern matching is fine. +</span><span> </span><span style="color:#999999;">// 2. We *borrowed* the value, so we can use it after the match. +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;John is </span><span style="color:#666969;">{}</span><span style="color:#718c00;"> years old and still kicking!&quot;</span><span>, john.age); +</span><span> +</span><span> </span><span style="color:#999999;">// To save some time, we can use `if let` to match against only one thing +</span><span> </span><span style="color:#999999;">// We could also use `while let ... {}` in the same way +</span><span> </span><span style="color:#8959a8;">if let </span><span>Color::Pink </span><span style="color:#3e999f;">= &amp;</span><span>john.favorite_color { +</span><span> println!(</span><span style="color:#718c00;">&quot;He&#39;s also a man of great taste&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can match ranges... +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">12 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a kid!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">13</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a teenager!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">20</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">29 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a young adult!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">30</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">49 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an adult!&quot;</span><span>), +</span><span> </span><span style="color:#f5871f;">50</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">69 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is mature!&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is old!&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use match and capture the value at the same time. +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">12 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a kid, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">13</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a teenager, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">20</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">29 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is a young adult, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">30</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">49 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an adult, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">50</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">69 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is mature, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is old, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use guards to check for multiple conditions. +</span><span> </span><span style="color:#8959a8;">match</span><span> john.age { +</span><span> age </span><span style="color:#3e999f;">@ </span><span style="color:#f5871f;">12</span><span style="color:#3e999f;">..=</span><span style="color:#f5871f;">19 </span><span style="color:#8959a8;">if</span><span> age </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an *odd* teenager, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> age </span><span style="color:#8959a8;">if</span><span> age </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is an *even* man, age </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, age), +</span><span> </span><span style="color:#3e999f;">_ =&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;John is normal&quot;</span><span>), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// Finally, let&#39;s look at some references now +</span><span> </span><span style="color:#8959a8;">let</span><span> reference: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= &amp;</span><span style="color:#f5871f;">4</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">match</span><span> reference { +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>val </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Value under reference is: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, val), +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// `ref` can be used to create a reference when destructuring +</span><span> </span><span style="color:#8959a8;">let</span><span> Human { +</span><span> age, +</span><span> </span><span style="color:#8959a8;">ref</span><span> favorite_color, +</span><span> } </span><span style="color:#3e999f;">=</span><span> john; +</span><span> </span><span style="color:#999999;">// `john` is still valid, because we borrowed using `ref` +</span><span> </span><span style="color:#8959a8;">if let </span><span>Color::Pink </span><span style="color:#3e999f;">= &amp;</span><span>john.favorite_color { +</span><span> println!(</span><span style="color:#718c00;">&quot;John still has his color - </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">!&quot;</span><span>, favorite_color); +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> john </span><span style="color:#3e999f;">=</span><span> john; +</span><span> +</span><span> </span><span style="color:#999999;">// `ref mut` borrows mutably +</span><span> </span><span style="color:#8959a8;">let</span><span> Human { +</span><span> age, +</span><span> </span><span style="color:#8959a8;">ref mut</span><span> favorite_color, +</span><span> } </span><span style="color:#3e999f;">=</span><span> john; +</span><span> </span><span style="color:#999999;">// We use `*` to dereference +</span><span> </span><span style="color:#3e999f;">*</span><span>favorite_color </span><span style="color:#3e999f;">= </span><span>Color::Brown; +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Tastes do change with time and John likes </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;"> now.&quot;</span><span>, +</span><span> john.favorite_color +</span><span> ); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/pattern_matching.rs">pattern_matching.rs</a>)</sub></p> +<h2 id="result">Result</h2> +<p>We said there are no exceptions in Rust and panics mean errors which cannot be caught. +So how do we handle situations which can fail? That's where the <code>Result</code> type comes in.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(dead_code)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">use </span><span>std::fs::File; +</span><span style="color:#8959a8;">use </span><span>std::io; +</span><span style="color:#8959a8;">use </span><span>std::io::Read; +</span><span> +</span><span style="color:#999999;">// Let&#39;s try reading from a file. +</span><span style="color:#999999;">// Obviously this can fail. +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">first_try</span><span>() -&gt; io::</span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">let</span><span> file </span><span style="color:#3e999f;">= </span><span>File::open(</span><span style="color:#718c00;">&quot;/dev/random&quot;</span><span>); +</span><span> </span><span style="color:#8959a8;">match</span><span> file { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#8959a8;">mut</span><span> file) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#999999;">// We got a file! +</span><span> </span><span style="color:#8959a8;">let mut</span><span> buffer </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#f5871f;">128</span><span>]; +</span><span> </span><span style="color:#999999;">// Matching each result quickly become tedious... +</span><span> </span><span style="color:#8959a8;">match</span><span> file.</span><span style="color:#4271ae;">read_exact</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> buffer) { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(</span><span style="color:#3e999f;">_</span><span>) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> gibberish </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from_utf8_lossy(</span><span style="color:#3e999f;">&amp;</span><span>buffer); +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish.</span><span style="color:#4271ae;">to_string</span><span>()) +</span><span> } +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span style="color:#c99e00;">Err</span><span>(error), +</span><span> } +</span><span> } +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span>{ +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#999999;">// This is needed in order to change the type from `io::Result&lt;File&gt;` to `io::Result&lt;()&gt;` +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// The &#39;?&#39; operator allows us to return early in case of an error +</span><span style="color:#999999;">// (it automatically converts the error type) +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">second_try</span><span>(</span><span style="color:#f5871f;">filename</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">&#39;static str</span><span>) -&gt; io::</span><span style="color:#c99e00;">Result</span><span>&lt;</span><span style="color:#c99e00;">String</span><span>&gt; { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> file </span><span style="color:#3e999f;">= </span><span>File::open(filename)</span><span style="color:#3e999f;">?</span><span>; +</span><span> </span><span style="color:#8959a8;">let mut</span><span> buffer </span><span style="color:#3e999f;">= </span><span>vec![</span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#f5871f;">128</span><span>]; +</span><span> file.</span><span style="color:#4271ae;">read_exact</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> buffer)</span><span style="color:#3e999f;">?</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> gibberish </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from_utf8_lossy(</span><span style="color:#3e999f;">&amp;</span><span>buffer); +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish.</span><span style="color:#4271ae;">to_string</span><span>()) +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> filenames </span><span style="color:#3e999f;">= </span><span>[ +</span><span> </span><span style="color:#718c00;">&quot;/dev/random&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/null&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/cpu&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;/dev/fuse&quot;</span><span>, +</span><span> </span><span style="color:#718c00;">&quot;there_certainly_is_no_such_file&quot;</span><span>, +</span><span> ]; +</span><span> </span><span style="color:#8959a8;">for</span><span> filename </span><span style="color:#3e999f;">in</span><span> filenames { +</span><span> println!(</span><span style="color:#718c00;">&quot;Trying to read from &#39;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&#39;&quot;</span><span>, filename); +</span><span> </span><span style="color:#8959a8;">match </span><span style="color:#4271ae;">second_try</span><span>(filename) { +</span><span> </span><span style="color:#c99e00;">Ok</span><span>(gibberish) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, gibberish), +</span><span> </span><span style="color:#c99e00;">Err</span><span>(error) </span><span style="color:#3e999f;">=&gt; </span><span>println!(</span><span style="color:#718c00;">&quot;Error: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, error), +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/04-enums/result.rs">result.rs</a>)</sub></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li>The Book, chapters <a href="https://doc.rust-lang.org/stable/book/ch06-00-enums.html">6</a>, +<a href="https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html">8</a> +and <a href="https://doc.rust-lang.org/stable/book/ch09-00-error-handling.html">9</a></li> +<li><a href="https://doc.rust-lang.org/std/option/">Option docs</a></li> +<li><a href="https://doc.rust-lang.org/std/result/">Result docs</a></li> +</ul> +<h2 id="assignment-2-graded">Assignment #2 (graded)</h2> +<p><a href="https://classroom.github.com/a/KGDd4ofC">Here</a> you can find the second graded assignment. Deadline for submissions is 24.03.2022.</p> + + + + + Tests + 2022-03-13T00:00:00+00:00 + 2022-03-13T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/05-tests/ + + <h1 id="unit-testing">Unit testing!</h1> +<p>Rust has a built-in testing framework.</p> +<p>You can write <code>cargo test</code> to run all tests.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#999999;">// This function is going to be used only in the tests, so we add the `#[cfg(test)]` attribute. +</span><span style="color:#999999;">// It means that it won&#39;t be compiled in the final executable. +</span><span>#[</span><span style="color:#c82829;">cfg</span><span>(test)] +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">return_42</span><span>() -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> </span><span style="color:#f5871f;">42 +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">frobnicate</span><span>(</span><span style="color:#f5871f;">x</span><span>: </span><span style="color:#8959a8;">i32</span><span>) -&gt; </span><span style="color:#8959a8;">i32 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;frobicating...!&quot;</span><span>); +</span><span> x </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">40 +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#4271ae;">frobnicate</span><span>(</span><span style="color:#f5871f;">2</span><span>); +</span><span>} +</span><span> +</span><span>#[</span><span style="color:#c82829;">cfg</span><span>(test)] +</span><span style="color:#8959a8;">mod </span><span>tests { +</span><span> </span><span style="color:#8959a8;">use super</span><span>::</span><span style="color:#3e999f;">*</span><span>; +</span><span> +</span><span> #[</span><span style="color:#c82829;">test</span><span>] +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">it_works</span><span>() { +</span><span> assert_eq!(</span><span style="color:#4271ae;">return_42</span><span>(), </span><span style="color:#f5871f;">42</span><span>); +</span><span> } +</span><span> +</span><span> #[</span><span style="color:#c82829;">test</span><span>] +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">test_frobnicate</span><span>() { +</span><span> assert_eq!(</span><span style="color:#4271ae;">frobnicate</span><span>(</span><span style="color:#f5871f;">2</span><span>), </span><span style="color:#f5871f;">42</span><span>); +</span><span> } +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/05-tests/test.rs">test.rs</a>)</sub></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/book/ch11-00-testing.html">The Book, chapter 11</a></li> +</ul> + + + + + Introduction to Rust + 2022-03-09T00:00:00+00:00 + 2022-03-09T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/ + + <p><img src="https://www.rust-lang.org/logos/rust-logo-blk.svg" alt="Logo" /></p> +<h2 id="why-use-rust">Why use Rust?</h2> +<ul> +<li>It is <strong>safe</strong> (compared to C++ for example, as we will see in a minute)</li> +<li>It is <strong>fast</strong> (because it is compiled to machine code)</li> +<li>It is ergonomic and pleasant to use (static typing, expressive type system, helpful compiler +warnings)</li> +<li>It +is <a href="https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-programming-scripting-and-markup-languages">loved by programmers</a></li> +<li>It provides excellent tooling</li> +</ul> +<h2 id="why-learn-rust">Why learn Rust?</h2> +<p>Even if you don't end up using Rust, learning it expands your horizons</p> +<ul> +<li>it helps especially with the awareness of what you can and can't do in concurrent applications</li> +<li>it helps you understand memory management and learn its good practices</li> +</ul> +<h2 id="why-not-to-learn-rust">Why not to learn Rust?</h2> +<ul> +<li>Some people say Rust is too hard to learn because of the borrow checker</li> +<li>Once you get to know Cargo you won't ever want to use a language without a built-in package +manager ;)</li> +<li>You will start hating C++ (Piotrek, don't punch me!)</li> +</ul> +<h2 id="demo">Demo</h2> +<p>Let's compare the same code written in <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/errors_demo.c">C</a>, <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/errors_demo.cpp">C++</a> +and <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/errors_demo.rs">Rust</a>.</p> +<h2 id="installing-rust">Installing Rust</h2> +<ul> +<li><a href="https://rustup.rs/">Rustup</a></li> +<li>Setup an IDE +<ul> +<li><a href="https://www.jetbrains.com/clion/">CLion</a> (you can get +it <a href="https://www.jetbrains.com/community/education/">for free</a>) +and <a href="https://intellij-rust.github.io/">Intellij-Rust</a></li> +<li><a href="https://code.visualstudio.com/">VSCode</a> +and <a href="https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer">rust-analyzer</a></li> +<li>rust-analyzer also works +with <a href="https://rust-analyzer.github.io/manual.html#installation">other IDEs</a></li> +</ul> +</li> +</ul> +<h2 id="useful-tools">Useful tools</h2> +<p><img src="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/clippy.jpg" alt="Clippy" /></p> +<ul> +<li><code>cargo clippy</code> (for static analysis)</li> +<li>there's also <code>cargo check</code>, but it's less powerful than clippy</li> +<li><code>cargo fmt</code> (for code formatting)</li> +</ul> +<h3 id="rust-playground">Rust Playground</h3> +<ul> +<li><a href="https://play.rust-lang.org/">online Rust compiler</a></li> +</ul> +<h2 id="hello-world">Hello world</h2> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> name </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;World&quot;</span><span>; +</span><span> println!(</span><span style="color:#718c00;">&quot;Hello, </span><span style="color:#666969;">{}</span><span style="color:#718c00;">!&quot;</span><span>, name); </span><span style="color:#999999;">// using the println! macro +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/hello_world.rs">hello_world.rs</a>)</sub></p> +<h3 id="variables">Variables</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_assignments)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40</span><span>; </span><span style="color:#999999;">// inferred type +</span><span> </span><span style="color:#8959a8;">let</span><span> y: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">100</span><span>; </span><span style="color:#999999;">// specified type +</span><span> +</span><span> { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40 </span><span style="color:#3e999f;">+ </span><span style="color:#f5871f;">2</span><span>; </span><span style="color:#999999;">// shadowing +</span><span> println!(</span><span style="color:#718c00;">&quot;x is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, x); </span><span style="color:#999999;">// prints 42 +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// x = 0; // compilation error, variables are by default immutable +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">40</span><span>; </span><span style="color:#999999;">// declare as mutable +</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; </span><span style="color:#999999;">// now we can reassign +</span><span> +</span><span> x </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; </span><span style="color:#999999;">// x = x + 1 +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/variables.rs">variables.rs</a>)</sub></p> +<h3 id="conditionals">Conditionals</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">42</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">42 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is 42&quot;</span><span>); +</span><span> } </span><span style="color:#8959a8;">else if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">43 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is 43&quot;</span><span>); +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;x is not 42 or 43&quot;</span><span>); +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// we can also use ifs as expressions +</span><span> </span><span style="color:#8959a8;">let</span><span> a_or_b </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">if</span><span> x </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;a&quot; </span><span style="color:#999999;">// notice no semicolon at the end +</span><span> } </span><span style="color:#8959a8;">else </span><span>{ +</span><span> </span><span style="color:#718c00;">&quot;b&quot; +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/conditionals.rs">conditionals.rs</a>)</sub></p> +<h3 id="loops">Loops</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#![</span><span style="color:#c82829;">allow</span><span>(unused_variables)] +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">for</span><span> i </span><span style="color:#3e999f;">in </span><span style="color:#f5871f;">0</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">10 </span><span>{ +</span><span> println!(</span><span style="color:#718c00;">&quot;i is </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, i); </span><span style="color:#999999;">// i in [0, 10) +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> x </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">while</span><span> x </span><span style="color:#3e999f;">&lt; </span><span style="color:#f5871f;">50 </span><span>{ +</span><span> x </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> y </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let mut</span><span> iterations </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> iterations </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> iterations </span><span style="color:#3e999f;">% </span><span style="color:#f5871f;">2 </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">0 </span><span>{ +</span><span> </span><span style="color:#8959a8;">continue</span><span>; +</span><span> } +</span><span> y </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> y </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// we can use labels to refer to a specific loop +</span><span> </span><span style="color:#8959a8;">let mut</span><span> count </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> &#39;counting_up: </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> </span><span style="color:#8959a8;">let mut</span><span> remaining </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">10</span><span>; +</span><span> +</span><span> </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> </span><span style="color:#8959a8;">if</span><span> remaining </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">9 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break</span><span>; +</span><span> } +</span><span> </span><span style="color:#8959a8;">if</span><span> count </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">2 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break &#39;counting_up</span><span>; </span><span style="color:#999999;">// ends the outer loop +</span><span> } +</span><span> remaining </span><span style="color:#3e999f;">-= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> count </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// We can use break with a value. +</span><span> </span><span style="color:#999999;">// Because loops are expressions too, +</span><span> </span><span style="color:#999999;">// the value we break with will be returned from the functions +</span><span> </span><span style="color:#8959a8;">let mut</span><span> counter </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#8959a8;">let</span><span> value </span><span style="color:#3e999f;">= </span><span style="color:#8959a8;">loop </span><span>{ +</span><span> counter </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> </span><span style="color:#8959a8;">if</span><span> counter </span><span style="color:#3e999f;">== </span><span style="color:#f5871f;">10 </span><span>{ +</span><span> </span><span style="color:#8959a8;">break </span><span style="color:#f5871f;">32</span><span>; +</span><span> } +</span><span> }; +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/loops.rs">loops.rs</a>)</sub></p> +<h3 id="functions">Functions</h3> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">get_5</span><span>() -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#f5871f;">5 </span><span style="color:#999999;">// we could also write &quot;return 5;&quot; +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">print_sum</span><span>(</span><span style="color:#f5871f;">a</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">b</span><span>: </span><span style="color:#8959a8;">u32</span><span>) { +</span><span> println!(</span><span style="color:#718c00;">&quot;a + b = </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, a </span><span style="color:#3e999f;">+</span><span> b); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> a </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">100</span><span>; +</span><span> </span><span style="color:#4271ae;">print_sum</span><span>(a, </span><span style="color:#4271ae;">get_5</span><span>()); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/01-introduction/functions.rs">functions.rs</a>)</sub></p> +<h2 id="test-assignment-not-graded">Test assignment (not graded)</h2> +<p>Click <a href="https://classroom.github.com/a/sFJOi1pT">here</a></p> +<h2 id="obligatory-reading">Obligatory reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/book/">The Book, chapters 1-3</a></li> +</ul> +<h2 id="additional-reading">Additional reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/stable/rust-by-example/">Rust By Example</a></li> +</ul> + + + + + Data Types + 2022-03-09T00:00:00+00:00 + 2022-03-09T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/03-data-types/ + + <h2 id="aggregating-data">Aggregating data</h2> +<p>Below is a compact overview of Rust's structs</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>#[</span><span style="color:#c82829;">derive</span><span>(Clone, Copy, Debug, Eq, PartialEq)] +</span><span style="color:#8959a8;">struct </span><span>Position(</span><span style="color:#8959a8;">i32</span><span>, </span><span style="color:#8959a8;">i32</span><span>); </span><span style="color:#999999;">// tuple struct +</span><span> +</span><span style="color:#999999;">// Could Hero derive the Copy trait? +</span><span>#[</span><span style="color:#c82829;">derive</span><span>(Clone, Debug, Eq, PartialEq)] +</span><span style="color:#8959a8;">struct </span><span>Hero { +</span><span> </span><span style="color:#c82829;">name</span><span>: String, +</span><span> </span><span style="color:#c82829;">level</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">experience</span><span>: </span><span style="color:#8959a8;">u32</span><span>, +</span><span> </span><span style="color:#c82829;">position</span><span>: Position, +</span><span>} +</span><span> +</span><span style="color:#999999;">// we can add methods to structs using the &#39;impl&#39; keyword +</span><span style="color:#8959a8;">impl </span><span>Hero { +</span><span> </span><span style="color:#999999;">// static method +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">new</span><span>(</span><span style="color:#f5871f;">name</span><span>: String) -&gt; Hero { +</span><span> Hero { +</span><span> name, +</span><span> level: </span><span style="color:#f5871f;">1</span><span>, +</span><span> experience: </span><span style="color:#f5871f;">0</span><span>, +</span><span> position: Position(</span><span style="color:#f5871f;">0</span><span>, </span><span style="color:#f5871f;">0</span><span>), +</span><span> } +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#999999;">// multiple impl blocks are possible for one struct +</span><span style="color:#8959a8;">impl </span><span>Hero { +</span><span> </span><span style="color:#999999;">// instance method, first argument (self) is the calling instance +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">distance</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#f5871f;">self</span><span>, </span><span style="color:#f5871f;">pos</span><span>: Position) -&gt; </span><span style="color:#8959a8;">u32 </span><span>{ +</span><span> </span><span style="color:#999999;">// fields of tuples and tuple structs can be accessed through &#39;tuple.[i]&#39; +</span><span> (pos.</span><span style="color:#f5871f;">0 </span><span style="color:#3e999f;">- </span><span style="color:#c82829;">self</span><span>.position.</span><span style="color:#f5871f;">0</span><span>).</span><span style="color:#4271ae;">unsigned_abs</span><span>() </span><span style="color:#3e999f;">+ </span><span>(pos.</span><span style="color:#f5871f;">1 </span><span style="color:#3e999f;">- </span><span style="color:#c82829;">self</span><span>.position.</span><span style="color:#f5871f;">1</span><span>).</span><span style="color:#4271ae;">unsigned_abs</span><span>() +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// mutable borrow of self allows to change instance fields +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">level_up</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut </span><span style="color:#f5871f;">self</span><span>) { +</span><span> </span><span style="color:#c82829;">self</span><span>.experience </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">0</span><span>; +</span><span> </span><span style="color:#c82829;">self</span><span>.level </span><span style="color:#3e999f;">+= </span><span style="color:#f5871f;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#999999;">// &#39;self&#39; is not borrowed here and will be moved into the method +</span><span> </span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">die</span><span>(</span><span style="color:#f5871f;">self</span><span>) { +</span><span> println!( +</span><span> </span><span style="color:#718c00;">&quot;Here lies </span><span style="color:#666969;">{}</span><span style="color:#718c00;">, a hero who reached level </span><span style="color:#666969;">{}</span><span style="color:#718c00;">. RIP.&quot;</span><span>, +</span><span> </span><span style="color:#c82829;">self</span><span>.name, </span><span style="color:#c82829;">self</span><span>.level +</span><span> ); +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> hero: Hero </span><span style="color:#3e999f;">= </span><span>Hero::new(</span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Marty The Brave&quot;</span><span>)); +</span><span> hero.</span><span style="color:#4271ae;">level_up</span><span>(); </span><span style="color:#999999;">// &#39;self&#39; is always passed implicitly +</span><span> +</span><span> </span><span style="color:#999999;">// fields other than &#39;name&#39; will be the same as in &#39;hero&#39; +</span><span> </span><span style="color:#8959a8;">let</span><span> steve </span><span style="color:#3e999f;">=</span><span> Hero { +</span><span> name: </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Steve The Normal Guy&quot;</span><span>), +</span><span> </span><span style="color:#3e999f;">..</span><span>hero +</span><span> }; +</span><span> +</span><span> assert_eq!(hero.level, steve.level); +</span><span> +</span><span> </span><span style="color:#8959a8;">let mut</span><span> twin </span><span style="color:#3e999f;">=</span><span> hero.</span><span style="color:#4271ae;">clone</span><span>(); +</span><span> +</span><span> </span><span style="color:#999999;">// we can compare Hero objects because it derives the PartialEq trait +</span><span> assert_eq!(hero, twin); +</span><span> twin.</span><span style="color:#4271ae;">level_up</span><span>(); +</span><span> assert_ne!(hero, twin); +</span><span> hero.</span><span style="color:#4271ae;">level_up</span><span>(); +</span><span> assert_eq!(hero, twin); +</span><span> +</span><span> </span><span style="color:#999999;">// we can print out a the struct&#39;s debug string with &#39;{:?}&#39; +</span><span> println!(</span><span style="color:#718c00;">&quot;print to stdout: </span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, hero); +</span><span> +</span><span> hero.</span><span style="color:#4271ae;">die</span><span>(); </span><span style="color:#999999;">// &#39;hero&#39; is not usable after this invocation, see the method&#39;s definiton +</span><span> +</span><span> </span><span style="color:#999999;">// the dbg! macro prints debug strings to stderr along with file and line number +</span><span> dbg!(</span><span style="color:#718c00;">&quot;print to stderr: {}&quot;</span><span>, twin); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> pos </span><span style="color:#3e999f;">=</span><span> Position(</span><span style="color:#f5871f;">42</span><span>, </span><span style="color:#f5871f;">0</span><span>); +</span><span> </span><span style="color:#8959a8;">let</span><span> dist </span><span style="color:#3e999f;">=</span><span> steve.</span><span style="color:#4271ae;">distance</span><span>(pos); </span><span style="color:#999999;">// no clone here as Position derives the Copy trait +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{:?}</span><span style="color:#718c00;">&quot;</span><span>, pos); +</span><span> assert_eq!(dist, </span><span style="color:#f5871f;">42</span><span>); +</span><span>} +</span><span> +</span></code></pre> +<p><sub>(Download the source code for this example: <a href="https://mimuw-jnp2-rust.github.io/lessons/old/2021L/03-data-types/data_types.rs">data_types.rs</a>)</sub></p> +<h2 id="further-reading">Further reading</h2> +<ul> +<li><a href="https://doc.rust-lang.org/book/ch05-00-structs.html">The Book, chapter 5</a></li> +</ul> +<h2 id="assignment-1-graded">Assignment #1 (graded)</h2> +<p><a href="https://classroom.github.com/a/nc92p2Ow">Here</a> you can find our first biweekly assignment. The deadline for submissions is 14.03.2022.</p> + + + + + Ownership Model + 2022-03-06T00:00:00+00:00 + 2022-03-06T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/02-ownership/ + + <h2 id="why-all-the-fuss">Why all the fuss?</h2> +<p>Even if you've never seen Rust code before, chances are you still heard the term <em>borrow checker</em> or something about Rust's ownership. Indeed, Rust's ownership model lies at the very core of its uniqueness. But to fully understand it and appreciate it, let's first take a look at how memory management is handled in most popular languages.</p> +<ul> +<li> +<p><strong>Garbage Collection</strong> - in many high-level programming languages, like Java, Haskell or Python, memory management is done fully by the language, relieving the programmer from this burden. This prevents memory leaks and memory related errors (like <em>use after free</em>), but does come at a cost - there is a runtime overhead, both memory and performance wise, caused by the constantly running garbage collection algorithms and the programmer usually has very little control over when the garbage collection takes place.</p> +</li> +<li> +<p><strong>Mind your own memory</strong> - in low-level languages and specific ones like C++, performance comes first so we cannot really afford to run expansive bookkeeping and cleaning algorithms. Most of these languages compile directly to machine code and have no language-specific runtime environment. That means that the only place where memory management can happen is in the produced code. While compilers insert these allocation and deallocation calls for stack allocated memory, it generally requires a lot of discipline from the programmer to adhere to good practices and patterns to avoid as many memory related issues as possible and one such bug can be quite deadly to the program and a nightmare to find and fix. These languages basically live by the <em>&quot;your memory, your problem&quot;</em> mantra.management of stack allocated memory</p> +</li> +</ul> +<p>And then we have Rust. Rust is a systems programming language and in many ways it's akin to C++ - it's basically low-level with many high-level additions. But unlike C++, it doesn't exactly fall into either of the categories described above, though it's way closer to the second one. It performs no additional management at runtime, but instead imposes a set of rules on the code, making it easier to reason about and thus check for its safety and correctness at compile time - these rules make up Rust's <strong>ownership model</strong>.</p> +<p>In a way, programming in Rust is like pair-programming with a patient and very experienced partner. Rust's compiler will make sure you follow all the good patterns and practices (by having them ingrained in the language itself) and very often even tell you how to fix the issues it finds.</p> +<p><em><strong>Disclaimer:</strong> when delving deeper into Rust below we will make heavy use of concepts like scopes, moving data, stack and heap, which should have been introduced as part of the JNP1 C++ course. If you need a refresher of any of these, it's best to do so now, before reading further.</em></p> +<h2 id="start-with-the-basics-ownership">Start with the basics - ownership</h2> +<p>In the paragraph above we mentioned a set of rules that comprise Rust's ownership model. <a href="https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ownership-rules">The book</a> starts off with the following three as its very foundation:</p> +<ol> +<li> +<p>Each value in Rust is tied to a specific variable - we call that variable its <strong>owner</strong>.</p> +</li> +<li> +<p>There can only be one owner at a time.</p> +</li> +<li> +<p>When the owner goes out of scope, the value will be destroyed (or in Rust terms - <em>dropped</em>).</p> +</li> +</ol> +<p>The third point might make you think about C++ and its automatic storage duration. We will later see that, while very similar at first, Rust expands on these mechanics quite a bit. The following code illustrates the basic version of this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> a: </span><span style="color:#8959a8;">i32 </span><span style="color:#3e999f;">= </span><span style="color:#f5871f;">5</span><span>; </span><span style="color:#999999;">// allocation on the stack, &#39;a&#39; becomes an owner +</span><span> +</span><span> </span><span style="color:#999999;">// do some stuff with &#39;a&#39; +</span><span> +</span><span>} </span><span style="color:#999999;">// &#39;a&#39;, the owner, goes out of scope and the value is dropped +</span></code></pre> +<p>So far, so good. Variables are pushed onto the stack when they enter the scope and destroyed during stack unwinding that happens upon leaving their scope. However, allocating and deallocating simple integers doesn't impress anybody. Let's try something more complex:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span>{ +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// &#39;s&#39; is allocated on the stack, while its contents (&quot;a string&quot;) +</span><span> </span><span style="color:#999999;">// are allocated on the heap. &#39;s&#39; is the owner of this String object. +</span><span> +</span><span> </span><span style="color:#999999;">// do some stuff with &#39;a&#39; +</span><span> +</span><span>} </span><span style="color:#999999;">// &#39;s&#39;, the owner, goes out of scope and the String is dropped, its heap allocated memory freed +</span></code></pre> +<p>If you recall the RAII (Resource Acquisition Is Initialization) pattern from C++, the above is basically the same thing. We go two for two now in the similarity department, so... is Rust really any different then? There is a part of these examples that we skipped over - actually doing something with the values.</p> +<h2 id="moving-around-is-fun">Moving around is fun</h2> +<p>Let's expand on the last example. The scoping is not really important for that one, so we don't include it here.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// same thing, &#39;s&#39; is now an owner +</span><span> +</span><span style="color:#8959a8;">let</span><span> s2 </span><span style="color:#3e999f;">=</span><span> s; </span><span style="color:#999999;">// easy, &#39;s2&#39; becomes another owner... right? +</span><span> +</span><span>println!(</span><span style="color:#718c00;">&quot;And the contents are: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s); </span><span style="color:#999999;">// this doesn&#39;t work, can you guess why? +</span></code></pre> +<p>At first glance everything looks great. If we write this code (well, an equivalent of it) in basically any other popular language, it will compile no issue - but it does not here and there's a good reason why.</p> +<p>To understand what's happening, we have to consult the rules again, rule 2 in particular. It says that there can only be one owner of any value at a given time. So, <code>s</code> and <code>s2</code> cannot own the same object. Okay, makes sense, but what is happening in this line then - <code>let s2 = s;</code>? Experience probably tells you that <code>s</code> just gets copied into <code>s2</code>, creating a new String object. That would result in each variable owning its very own instance of the string and each instance having exactly one owner. Sounds like everyone should be happy now, but wait - in that case the last line should work no issue, right? But it doesn't, so can't be a copy. Let's see now what the compiler actually has to say:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0382]: borrow of moved value: `s` +</span><span> --&gt; src/main.rs:6:42 +</span><span> | +</span><span>2 | let s = String::from(&quot;a string&quot;); +</span><span> | - move occurs because `s` has type `String`, which does not implement the `Copy` trait +</span><span>3 | +</span><span>4 | let s2 = s; +</span><span> | - value moved here +</span><span>5 | +</span><span>6 | println!(&quot;And the contents are: {}&quot;, s); +</span><span> | ^ value borrowed here after move +</span></code></pre> +<p><em>&quot;value moved here&quot;</em> - gotcha! So <code>s</code> is being moved to <code>s2</code>, which also means that <code>s2</code> now becomes the new owner of the string being moved and <code>s</code> is left in an invalid state. In Rust, the default method of passing values around is by move, not by copy. While it may sound a bit odd at first, it actually has some very interesting implications. But before we get to them, let's fix our code so it compiles now. To do so, we have to explicitly tell Rust to make a copy by invoking the <code>clone</code> method:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;a string&quot;</span><span>); </span><span style="color:#999999;">// &#39;s&#39; is an owner +</span><span> +</span><span style="color:#8959a8;">let</span><span> s2 </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">clone</span><span>(); </span><span style="color:#999999;">// &#39;s2&#39; now contains its own copy +</span><span> +</span><span>println!(</span><span style="color:#718c00;">&quot;And the contents are: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, s); </span><span style="color:#999999;">// success! +</span></code></pre> +<p>The compiler is happy now and so are we. The implicit move takes some getting used to, but the compiler is here to help us. Now, let's put the good, old C++ on the table again and compare the two lines:</p> +<div style="text-align: center"> +<p><code>let s2 = s;</code> is equivalent to <code>auto s2 = std::move(s);</code></p> +<p><code>let s2 = s.clone()</code> is equivalent to <code>auto s2 = s</code></p> +</div> +<p>There are a few important things to note here:</p> +<ul> +<li> +<p>Making a copy is oftentimes not cheap. Memory needs to be allocated and copied, and a call to the system has to be made. We should prefer to move things as much as possible to avoid this cost - in C++ we have a myriad of language features like <code>std::move</code> and <em>r-references</em> to achieve this. Every programmer worth their salt needs to be well versed in all of them to write efficient C++ code and simply forgetting one move can lead to significant performance loss (and this happens to even the most senior devs ever existing, let's not pretend). On the contrary, in Rust you need to make an effort to make a copy and that makes you very aware of the cost you're paying - something that we'll see quite a lot of in the language. Also, if you forget a clone there's no harm done - it just won't compile!</p> +</li> +<li> +<p>Hidden in all of this is another nice thing Rust gives us. In C++, nothing prevents you from using variables after they've been moved from, leading to unexpected errors in a more complex code. In Rust, that variable (in our case <code>s</code>) simply becomes invalid and the compiler gives us a nice error about it.</p> +</li> +</ul> +<h3 id="but-what-about-ints">But what about ints?</h3> +<p>A good question to ask. Copying primitives is cheap. And it's not convenient for the programmer to have to always write <code>.clone()</code> after every primitive. If we take a look at the error from the previous example:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>move occurs because `s` has type `String`, which does not implement the `Copy` trait` +</span></code></pre> +<p>It says that <code>s</code> was moved because the <code>String</code> type doesn't have the <code>Copy</code> trait. We will talk about traits more in depth in the future lessons, but what this basically means is that <code>String</code> is not specified to be copied by default. All primitive types (<code>i32</code>, <code>bool</code>, <code>f64</code>, <code>char</code>, etc.) and tuples consisting only of primitive types implement the <code>Copy</code> trait.</p> +<h3 id="exercise">Exercise</h3> +<p>How to fix that code?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, s); +</span><span>} +</span></code></pre> +<h2 id="let-s-borrow-some-books">Let's borrow some books</h2> +<p>We now know how to move things around and how to clone them if moving is not possible. But what if making a copy is unnecessary - maybe we just want to let someone look at our resource and keep on holding onto it once their done. Consider the following example:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(book.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Book is still there: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>Cloning is pretty excessive here. Imagine recommending a book to your friend and instead of lending it to them for the weekend, you scan it and print an exact copy. Not the best way to go about it, is it? Thankfully, Rust allows us to access a resource without becoming an owner through the use of references and the <code>&amp;</code> operator. This is called a borrow.</p> +<p>The adjusted code should look like this:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span>book); +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;Book is still there: </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>As with everything, references are too, by default, immutable, which means that the <code>read_book</code> function is not able to modify that book passed into it. We can also borrow something mutably by specifing it both in the receiving function signature and the place it gets called. Maybe you want to have your book signed by its author?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">sign_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> String) { +</span><span> book.</span><span style="color:#4271ae;">push_str</span><span>(</span><span style="color:#718c00;">&quot; ~ Arthur Author&quot;</span><span>); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#999999;">// note that the book has to be marked as mutable in the first place +</span><span> </span><span style="color:#8959a8;">let mut</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">sign_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> book); </span><span style="color:#999999;">// it&#39;s always clear when a parameter might get modified +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); </span><span style="color:#999999;">// book is now signed +</span><span>} +</span></code></pre> +<p>Pretty neat, but doesn't seem that safe right now. Let's try to surprise our friend:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">erase_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> String) { +</span><span> book.</span><span style="color:#4271ae;">clear</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">read_book</span><span>(</span><span style="color:#f5871f;">book</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;[Reading] </span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let mut</span><span> book </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;Merry lived in a big old house. The end.&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#8959a8;">let</span><span> r </span><span style="color:#3e999f;">= &amp;</span><span>book; </span><span style="color:#999999;">// an immutable borrow +</span><span> +</span><span> </span><span style="color:#4271ae;">erase_book</span><span>(</span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">mut</span><span> book); </span><span style="color:#999999;">// a mutable borrow +</span><span> +</span><span> </span><span style="color:#4271ae;">read_book</span><span>(r); </span><span style="color:#999999;">// would be pretty sad to open a blank book when it was not +</span><span> </span><span style="color:#999999;">// what we borrowed initially +</span><span> +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{}</span><span style="color:#718c00;">&quot;</span><span>, book); +</span><span>} +</span></code></pre> +<p>Fortunately for us (and our poor friend just wanting to read), the compiler steps in and doesn't let us do that, printing the following message:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0502]: cannot borrow `book` as mutable because it is also borrowed as immutable +</span><span> --&gt; src/main.rs:14:14 +</span><span> | +</span><span>12 | let r = &amp;book; // an immutable borrow +</span><span> | ----- immutable borrow occurs here +</span><span>13 | +</span><span>14 | erase_book(&amp;mut book); // a mutable borrow +</span><span> | ^^^^^^^^^ mutable borrow occurs here +</span><span>15 | +</span><span>16 | read_book(r); // would be pretty sad to open a blank book when it was not +</span><span> | - immutable borrow later used here +</span></code></pre> +<p>This is where the famous borrow checker comes in. To keep things super safe, Rust clearly states what can and cannot be done with references and tracks their lifetimes. Exactly one of the following is always true for references to a given resource:</p> +<ul> +<li> +<p>There exists only one mutable reference and no immutable references, <strong>or</strong></p> +</li> +<li> +<p>There is any number of immutable references and no mutable ones.</p> +</li> +</ul> +<p>You may notice a parallel to the <em>readers - writers</em> problem from concurrent programming. In fact, the way Rust's borrow checker is designed lends itself incredibly well to preventing data race related issues.</p> +<h3 id="dangling-references">Dangling references</h3> +<p>Rust also checks for dangling references. If we try to compile the following code:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> reference_to_nothing </span><span style="color:#3e999f;">= </span><span style="color:#4271ae;">dangle</span><span>(); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">dangle</span><span>() -&gt; </span><span style="color:#3e999f;">&amp;</span><span>String { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;hello&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#3e999f;">&amp;</span><span>s +</span><span>} +</span></code></pre> +<p>we will get an adequate error:</p> +<pre style="background-color:#ffffff;color:#4d4d4c;"><code><span>error[E0106]: missing lifetime specifier +</span><span> --&gt; src/main.rs:5:16 +</span><span> | +</span><span>5 | fn dangle() -&gt; &amp;String { +</span><span> | ^ expected named lifetime parameter +</span><span> | +</span><span> = help: this function&#39;s return type contains a borrowed value, but there is no value for it to be borrowed from +</span><span>help: consider using the `&#39;static` lifetime +</span><span> | +</span><span>5 | fn dangle() -&gt; &amp;&#39;static String { +</span><span> | ^^^^^^^^ +</span></code></pre> +<p>The message above suggests specifing a lifetime for the returned string. In Rust, the lifetime of each variable is also a part of its type, but we will talk more about it later.</p> +<h3 id="exercise-1">Exercise</h3> +<p>Our previous solution using <code>clone()</code> was pretty inefficient. How should this code look now?</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, s.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, s.</span><span style="color:#4271ae;">clone</span><span>()); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, s); </span><span style="color:#999999;">// we could&#39;ve ommitted the clone() here. Why? +</span><span>} +</span></code></pre> +<h2 id="everyone-gets-a-slice">Everyone gets a slice</h2> +<p>The last part of working with references that we will cover in this lesson are slices. A <em>slice</em> in Rust is a view over continuous data. Let us start with a string slice - the <code>&amp;str</code> type.</p> +<p><em><strong>Note:</strong> for the purposes of these examples we assume we are working with ASCII strings. More comprehensive articles on handling strings are linked at the end of this lesson.</em></p> +<p>To create a string slice from the <code>String</code> object <code>s</code>, we can simply write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#f5871f;">1</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">3</span><span>]; </span><span style="color:#999999;">// creates a slice of length 2, starting with the character at index 1 +</span></code></pre> +<p>This makes use of the <code>&amp;</code> operator and Rust's range notation to specify the beginning and end of the slice. Thus, we can also write:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#f5871f;">2</span><span style="color:#3e999f;">..</span><span>]; </span><span style="color:#999999;">// everything from index 2 till the end +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">1</span><span>]; </span><span style="color:#999999;">// only the first byte +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">= &amp;</span><span>s[</span><span style="color:#3e999f;">..</span><span>]; </span><span style="color:#999999;">// the whole string as a slice +</span><span style="color:#8959a8;">let</span><span> slice </span><span style="color:#3e999f;">=</span><span> s.</span><span style="color:#4271ae;">as_str</span><span>(); </span><span style="color:#999999;">// also the whole string +</span></code></pre> +<p>You might have noticed that we always built <code>String</code> values using the <code>from()</code> method and never actually used the string literals directly. What type is a string literal then? Turns out it's the new string slice we just learned about!</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> slice: </span><span style="color:#3e999f;">&amp;</span><span style="color:#8959a8;">str </span><span style="color:#3e999f;">= </span><span style="color:#718c00;">&quot;string literal&quot;</span><span>; +</span></code></pre> +<p>In fact, it makes a lot sense - string literals, after all, are not allocated on the heap, but rather placed in a special section of the resulting binary. It's only natural we just reference that place with a slice.</p> +<p>Slices can also be taken from arrays:</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">let</span><span> array: [</span><span style="color:#8959a8;">i32</span><span>; </span><span style="color:#f5871f;">4</span><span>] </span><span style="color:#3e999f;">= </span><span>[</span><span style="color:#f5871f;">42</span><span>, </span><span style="color:#f5871f;">10</span><span>, </span><span style="color:#f5871f;">5</span><span>, </span><span style="color:#f5871f;">2</span><span>]; </span><span style="color:#999999;">// creates an array of four 32 bit integers +</span><span style="color:#8959a8;">let</span><span> slice: </span><span style="color:#3e999f;">&amp;</span><span>[</span><span style="color:#8959a8;">i32</span><span>] </span><span style="color:#3e999f;">= &amp;</span><span>array[</span><span style="color:#f5871f;">1</span><span style="color:#3e999f;">..</span><span style="color:#f5871f;">3</span><span>]; </span><span style="color:#999999;">// results in a slice [10, 5] +</span></code></pre> +<h3 id="exercise-2">Exercise</h3> +<p>Can this code still be improved from the previous version utilizing references? Think about the signature of <code>count_animals</code>.</p> +<pre data-lang="rust" style="background-color:#ffffff;color:#4d4d4c;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">num</span><span>: </span><span style="color:#8959a8;">u32</span><span>, </span><span style="color:#f5871f;">animal</span><span>: </span><span style="color:#3e999f;">&amp;</span><span>String) { +</span><span> println!(</span><span style="color:#718c00;">&quot;</span><span style="color:#666969;">{} {}</span><span style="color:#718c00;"> ...&quot;</span><span>, num, animal); +</span><span>} +</span><span> +</span><span style="color:#8959a8;">fn </span><span style="color:#4271ae;">main</span><span>() { +</span><span> </span><span style="color:#8959a8;">let</span><span> s </span><span style="color:#3e999f;">= </span><span style="color:#c99e00;">String</span><span>::from(</span><span style="color:#718c00;">&quot;sheep&quot;</span><span>); +</span><span> +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">1</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">2</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span> </span><span style="color:#4271ae;">count_animals</span><span>(</span><span style="color:#f5871f;">3</span><span>, </span><span style="color:#3e999f;">&amp;</span><span>s); +</span><span>} +</span></code></pre> +<h3 id="further-reading">Further reading</h3> +<ul> +<li> +<p><a href="https://doc.rust-lang.org/std/primitive.char.html">Char documentation</a></p> +</li> +<li> +<p><a href="https://fasterthanli.me/articles/working-with-strings-in-rust">Working with strings in Rust</a></p> +</li> +<li> +<p><a href="https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html">The Book, chapter 4</a></p> +</li> +</ul> + + + + + Oragnizational lesson + 2022-02-16T00:00:00+00:00 + 2022-02-16T00:00:00+00:00 + + Unknown + + + https://mimuw-jnp2-rust.github.io/lessons/old/2021L/00-organizational/ + + <h1 id="jnp-2-rust">JNP 2: Rust</h1> +<p>We will be using <a href="https://classroom.github.com/">Github Classroom</a> for task submission. +Once you are enrolled in the Moodle course we will import the data into Classroom.</p> +<p>Our main learning/teaching resource will be <a href="https://doc.rust-lang.org/stable/book/">&quot;The Book&quot;</a>.</p> +<h2 id="schedule">Schedule</h2> +<ol> +<li>2022-03-01: Introduction. Setting up the environment. Why Rust? &quot;Hello world&quot;.</li> +<li>2022-03-08: Ownership and borrow checking. Data types and structures.</li> +<li>2022-03-15: Enums. Pattern matching. Option and Result. Cargo test.</li> +<li>2022-03-22: Reasoning about types - generics, traits and lifetimes.</li> +<li>2022-03-29: Closures and iterators.</li> +</ol> +<h2 id="grading">Grading</h2> +<ul> +<li>1/3 of the grade is based on small tasks. There will be approximately 1 task every two weeks and each task will be graded on a scale of 0 to 3.</li> +<li>2/3 of the grade is based on a big project. You can choose a topic yourself, but it must be accepted by us. The project has to be split into two parts. It can be done in groups of two.</li> +<li>The grade may be increased by a bonus. You can get a bonus for: +<ul> +<li>Making a presentation about some advanced topic (const generics, futures, macros, etc.) or about architecture of a selected Rust open-source library</li> +<li>Contributing to a selected Rust open-source library</li> +<li>Contributing to this course's materials</li> +</ul> +</li> +</ul> +<h2 id="project-deadlines">Project Deadlines</h2> +<ol> +<li>2022-04-12: Project ideas should be presented to us for further refining. If you wish to pair up with someone, now is the time to tell us.</li> +<li>2022-04-26: Final project ideas should be accepted by now.</li> +<li>2022-05-24: Deadline for submitting the first part of the project.</li> +<li>2022-06-21: Deadline for submitting the second and final part of the project.</li> +</ol> + + + + diff --git a/book.css b/book.css new file mode 100644 index 0000000..d6a657c --- /dev/null +++ b/book.css @@ -0,0 +1 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;text-size-adjust:100%;}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible;}pre{font-family:monospace;font-size:1em;}a{background-color:rgba(0,0,0,0)}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted;}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em;}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0;}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{appearance:textfield;outline-offset:-2px;}[type=search]::-webkit-search-decoration{appearance:none}::-webkit-file-upload-button{appearance:button;font:inherit;}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}*{box-sizing:border-box}html{font-size:62.5%}body,html{height:100%}body{text-rendering:optimizelegibility;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;letter-spacing:.2px}.menu{height:100%;position:absolute;left:0;overflow-y:auto;width:300px;color:#364149;background:#fafafa;border-right:1px solid rgba(0,0,0,.07);transition:.5s}.menu ul{list-style:none;margin:0;padding:0}.menu ul a{display:block;color:#364149;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;text-decoration:none;padding:10px 15px}.menu ul a:hover{text-decoration:underline}.menu ul li.active>a{color:#008cff;text-decoration:none}.menu ul ul{padding-left:20px}.menu-hidden{width:0}@media screen and (max-width: 600px){.menu{width:calc(100% - 100px);z-index:1}.menu-hidden{width:0;z-index:0}}.page-without-menu{width:100%;left:0}.page-without-menu .previous{left:15px}.page{position:absolute;width:calc(100% - 300px);height:100%;overflow-y:auto;color:#000;background:#fff;padding-bottom:20px;transition:.5s}.page .zola-anchor{color:#4183c4;padding-left:10px;text-decoration:none;font-weight:initial}.page .zola-anchor:hover{text-decoration:underline}.page img{max-width:100%}.page__content{font-size:1.6rem;word-wrap:break-word;line-height:1.7;position:relative;left:0;max-width:800px;margin:0 auto;padding:0 15px 40px}.page__content a{color:#4183c4;text-decoration:none}.page__content a:hover{text-decoration:underline}.page__content hr{height:4px;padding:0;margin:1.7em 0;overflow:hidden;background-color:#e7e7e7;border:none}.page__content pre{padding:1rem}.page__content pre span{white-space:pre-wrap}.page__content blockquote{margin:0;margin-bottom:.85em;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5}.page__content code{display:inline-block;vertical-align:middle;padding:.1em .3em;border-radius:3px;background:#f1f1f1;font-size:.875em;font-family:"Source Code Pro",Consolas,"Ubuntu Mono",Menlo,"DejaVu Sans Mono",monospace}.page__content pre code{background:none}.page__content iframe{border:0}.page__content table{margin:0 auto;border-collapse:collapse;border-color:#ccc}.page__content table td{padding:3px 20px;border:1px solid #ccc}.page__content table thead th{padding:6px 13px;font-weight:bold;border:1px solid #ccc}.page__content p{margin-top:0;margin-bottom:.85em}.page .previous{left:300px;float:left;transition:left .5s}.page .next{right:15px;float:right}.page .previous,.page .next{position:fixed;display:flex;top:50px;bottom:0;font-size:2.5em;color:#ccc;text-decoration:none;text-align:center;margin:0;max-width:150px;min-width:90px;justify-content:center;align-content:center;flex-direction:column}.page .previous:hover,.page .next:hover{color:#333}@media screen and (max-width: 1250px){.page .previous,.page .next{position:static;top:auto;display:inline-block;max-width:49%;width:49%}.page .previous:hover,.page .next:hover{text-decoration:none}}@media screen and (min-width: 600px){.page{left:300px}}@media screen and (max-width: 600px){.page{width:100%;left:calc(100% - 100px)}.page-without-menu{left:0}}.search-container{display:none}.search-container--is-visible{display:block}.search-container #search{width:100%;padding:1rem;border:1px solid #aaa;border-radius:3px;background-color:#fafafa;color:#000}.search-container .search-results__header{font-weight:bold;padding:1rem 0}.search-container .search-results__items{margin:0;padding:0;list-style:none}.search-container .search-results__item{margin-bottom:1rem}.search-container .search-results__teaser{font-size:90%}.search-mode .prev-link,.search-mode .next-link{display:none}.page-header{height:50px}.page-header .menu-icon{height:50px;width:50px;font-size:24px;text-align:center;float:left;position:relative;transition:background .5s;cursor:pointer}@keyframes clickfirst{0%{transform:translateY(6px) rotate(0deg)}100%{transform:translateY(0) rotate(45deg)}}@keyframes clickmid{0%{opacity:1}100%{opacity:0}}@keyframes clicklast{0%{transform:translateY(-6px) rotate(0deg)}100%{transform:translateY(0) rotate(-45deg)}}@keyframes outfirst{0%{transform:translateY(0) rotate(-45deg)}100%{transform:translateY(-6px) rotate(0deg)}}@keyframes outmid{0%{opacity:0}100%{opacity:1}}@keyframes outlast{0%{transform:translateY(0) rotate(45deg)}100%{transform:translateY(6px) rotate(0deg)}}.page-header .menu-icon span{position:absolute;left:calc((100% - 20px)/2);top:calc((100% - 1px)/2);width:20px;height:2px;background-color:rgba(0,0,0,.5)}.page-header .menu-icon span:nth-child(1){transform:translateY(6px) rotate(0deg)}.page-header .menu-icon span:nth-child(3){transform:translateY(-6px) rotate(0deg)}.page-header .menu-icon.icon-click span:nth-child(1){animation-duration:.5s;animation-fill-mode:both;animation-name:clickfirst}.page-header .menu-icon.icon-click span:nth-child(2){animation-duration:.2s;animation-fill-mode:both;animation-name:clickmid}.page-header .menu-icon.icon-click span:nth-child(3){animation-duration:.5s;animation-fill-mode:both;animation-name:clicklast}.page-header .menu-icon.icon-out span:nth-child(1){animation-duration:.5s;animation-fill-mode:both;animation-name:outfirst}.page-header .menu-icon.icon-out span:nth-child(2){animation-duration:.2s;animation-fill-mode:both;animation-name:outmid}.page-header .menu-icon.icon-out span:nth-child(3){animation-duration:.5s;animation-fill-mode:both;animation-name:outlast}.page-header .menu-icon:hover span{background-color:#000}.page-header .search-icon{height:50px;width:50px;display:inline-block;text-align:center;line-height:50px;color:rgba(0,0,0,.5);cursor:pointer;font-size:2rem}.page-header .search-icon:hover{color:#000}pre{padding:1rem;overflow:auto}pre[data-linenos]{padding:1rem 0}pre table td{padding:0}pre table td:nth-of-type(1){text-align:center;user-select:none}pre mark{display:block;background-color:rgba(254,252,232,.9)}pre table{width:100%;border-collapse:collapse} \ No newline at end of file diff --git a/book.js b/book.js new file mode 100644 index 0000000..83fbcde --- /dev/null +++ b/book.js @@ -0,0 +1,232 @@ +let elasticlunr; + +function initToggleMenu() { + const $menu = document.querySelector(".menu"); + const $menuIcon = document.querySelector(".menu-icon"); + const $page = document.querySelector(".page"); + $menuIcon.addEventListener("click", () => { + $menu.classList.toggle("menu-hidden"); + $page.classList.toggle("page-without-menu"); + }); +} + +function debounce(func, wait) { + let timeout; + + return () => { + const context = this; + const args = arguments; + clearTimeout(timeout); + + timeout = setTimeout(() => { + timeout = null; + func.apply(context, args); + }, wait); + }; +} + +// Taken from mdbook +// The strategy is as follows: +// First, assign a value to each word in the document: +// Words that correspond to search terms (stemmer aware): 40 +// Normal words: 2 +// First word in a sentence: 8 +// Then use a sliding window with a constant number of words and count the +// sum of the values of the words within the window. Then use the window that got the +// maximum sum. If there are multiple maximas, then get the last one. +// Enclose the terms in . +function makeTeaser(body, terms) { + const TERM_WEIGHT = 40; + const NORMAL_WORD_WEIGHT = 2; + const FIRST_WORD_WEIGHT = 8; + const TEASER_MAX_WORDS = 30; + + const stemmedTerms = terms.map((w) => elasticlunr.stemmer(w.toLowerCase())); + let termFound = false; + let index = 0; + const weighted = []; // contains elements of ["word", weight, index_in_document] + + // split in sentences, then words + const sentences = body.toLowerCase().split(". "); + + for (const i in sentences) { + const words = sentences[i].split(" "); + let value = FIRST_WORD_WEIGHT; + + for (const j in words) { + const word = words[j]; + + if (word.length > 0) { + for (const k in stemmedTerms) { + if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) { + value = TERM_WEIGHT; + termFound = true; + } + } + weighted.push([word, value, index]); + value = NORMAL_WORD_WEIGHT; + } + + index += word.length; + index += 1; // ' ' or '.' if last word in sentence + } + + index += 1; // because we split at a two-char boundary '. ' + } + + if (weighted.length === 0) { + return body; + } + + const windowWeights = []; + const windowSize = Math.min(weighted.length, TEASER_MAX_WORDS); + // We add a window with all the weights first + let curSum = 0; + for (let i = 0; i < windowSize; i++) { + curSum += weighted[i][1]; + } + windowWeights.push(curSum); + + for (let i = 0; i < weighted.length - windowSize; i++) { + curSum -= weighted[i][1]; + curSum += weighted[i + windowSize][1]; + windowWeights.push(curSum); + } + + // If we didn't find the term, just pick the first window + let maxSumIndex = 0; + if (termFound) { + let maxFound = 0; + // backwards + for (let i = windowWeights.length - 1; i >= 0; i--) { + if (windowWeights[i] > maxFound) { + maxFound = windowWeights[i]; + maxSumIndex = i; + } + } + } + + const teaser = []; + let startIndex = weighted[maxSumIndex][2]; + for (let i = maxSumIndex; i < maxSumIndex + windowSize; i++) { + const word = weighted[i]; + if (startIndex < word[2]) { + // missing text from index to start of `word` + teaser.push(body.substring(startIndex, word[2])); + startIndex = word[2]; + } + + // add around search terms + if (word[1] === TERM_WEIGHT) { + teaser.push(""); + } + startIndex = word[2] + word[0].length; + teaser.push(body.substring(word[2], startIndex)); + + if (word[1] === TERM_WEIGHT) { + teaser.push(""); + } + } + teaser.push("…"); + return teaser.join(""); +} + +function formatSearchResultItem(item, terms) { + const li = document.createElement("li"); + li.classList.add("search-results__item"); + li.innerHTML = `${item.doc.title}`; + li.innerHTML += `
${makeTeaser( + item.doc.body, + terms + )}
`; + return li; +} + +// Go from the book view to the search view +function toggleSearchMode() { + const $bookContent = document.querySelector(".book-content"); + const $searchContainer = document.querySelector(".search-container"); + if ($searchContainer.classList.contains("search-container--is-visible")) { + $searchContainer.classList.remove("search-container--is-visible"); + document.body.classList.remove("search-mode"); + $bookContent.style.display = "block"; + } else { + $searchContainer.classList.add("search-container--is-visible"); + document.body.classList.add("search-mode"); + $bookContent.style.display = "none"; + document.getElementById("search").focus(); + } +} + +function initSearch() { + const $searchInput = document.getElementById("search"); + if (!$searchInput) { + return; + } + const $searchIcon = document.querySelector(".search-icon"); + $searchIcon.addEventListener("click", toggleSearchMode); + + const $searchResults = document.querySelector(".search-results"); + const $searchResultsHeader = document.querySelector( + ".search-results__header" + ); + const $searchResultsItems = document.querySelector(".search-results__items"); + const MAX_ITEMS = 10; + + const options = { + bool: "AND", + fields: { + title: { boost: 2 }, + body: { boost: 1 }, + }, + }; + let currentTerm = ""; + const index = elasticlunr.Index.load(window.searchIndex); + + $searchInput.addEventListener( + "keyup", + debounce(() => { + const term = $searchInput.value.trim(); + if (term === currentTerm || !index) { + return; + } + $searchResults.style.display = term === "" ? "none" : "block"; + $searchResultsItems.innerHTML = ""; + if (term === "") { + return; + } + + const results = index + .search(term, options) + .filter((r) => r.doc.body !== ""); + if (results.length === 0) { + $searchResultsHeader.innerText = `No search results for '${term}'.`; + return; + } + + currentTerm = term; + $searchResultsHeader.innerText = `${results.length} search results for '${term}':`; + for (let i = 0; i < Math.min(results.length, MAX_ITEMS); i++) { + if (!results[i].doc.body) { + continue; + } + + $searchResultsItems.appendChild( + formatSearchResultItem(results[i], term.split(" ")) + ); + } + }, 150) + ); +} + +if ( + document.readyState === "complete" || + (document.readyState !== "loading" && !document.documentElement.doScroll) +) { + initToggleMenu(); +} else { + document.addEventListener("DOMContentLoaded", () => { + initToggleMenu(); + initSearch(); + }); +} diff --git a/elasticlunr.min.js b/elasticlunr.min.js new file mode 100644 index 0000000..79dad65 --- /dev/null +++ b/elasticlunr.min.js @@ -0,0 +1,10 @@ +/** + * elasticlunr - http://weixsong.github.io + * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.6 + * + * Copyright (C) 2017 Oliver Nightingale + * Copyright (C) 2017 Wei Song + * MIT Licensed + * @license + */ +!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o + + + + + + + Rust course + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
    +
    +
    + +
    + +

    JNP 2: Rust

    +

    This is a website for the JNP2: Rust course at MIM UW.

    +

    The course's instructor is Wojciech Przytuła (GitHub: wprzytula, e-mail: wp418383[at]students[dot]mimuw[dot]edu[dot]pl),

    +

    Instructori emeriti:

    +
      +
    • Piotr Wojtczak (GitHub: StarostaGit, e-mail: pw394980[at]students[dot]mimuw[dot]edu[dot]pl),
    • +
    • Andrzej Głuszak (GitHub: agluszak, e-mail: agluszak[at]mimuw[dot]edu[dot]pl).
    • +
    +

    You can find lesson scenarios here.

    +

    Contributions are welcome! ;)

    + + +
    +
    + + + + +
    + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/00-organizational/index.html b/lessons/00-organizational/index.html new file mode 100644 index 0000000..1f599d4 --- /dev/null +++ b/lessons/00-organizational/index.html @@ -0,0 +1,257 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
    + + +
    + +
    + +
    +
    +
      +
      +
      + +
      + +

      Organizational lesson

      +

      + 2024-10-03 (last edit: 2024-10-06) +

      +

      Rust course

      +

      We will be using Github Classroom for task submission and Discord for discussions.

      +

      Our main learning/teaching resource will be "The Book".

      +

      Also worth mentioning: "Rust by Example".

      +

      Grading

      +
        +
      • 1/3 of the grade is based on small tasks. There will be approximately 1 task every two weeks and each task will be graded on a scale of 0 to 3.
      • +
      • 2/3 of the grade is based on a big project. You can choose a topic yourself, but it must be accepted by me. The project has to be split into two parts. It can be done in groups of two (or bigger, if ambitious enough).
      • +
      • The grade may be increased by a bonus. You can get a bonus for: +
          +
        • Making a presentation about some advanced topic (const generics, futures, macros, etc.) or about architecture of a selected Rust open-source library
        • +
        • Contributing to a selected Rust open-source library
        • +
        • Contributing to this course's materials
        • +
        • Quizzes, homeworks, general activity etc.
        • +
        +
      • +
      +

      Project Deadlines

      +
        +
      1. 2024-11-7: Project ideas should be presented to me for further refining. If you wish to pair up with someone, now is the time to tell me.
      2. +
      3. 2024-11-14: Final project ideas should be accepted by now.
      4. +
      5. 2024-12-12: Deadline for submitting the first part of the project.
      6. +
      7. 2025-01-09: Deadline for submitting the second and final part of the project.
      8. +
      + + +
      +
      + + + + +
      + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.html b/lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.html new file mode 100644 index 0000000..10f5407 --- /dev/null +++ b/lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.html @@ -0,0 +1,4780 @@ + + + + + + + + + + + + + + + + +
      + +
      +
      + +
      +

      A taste of Rust

      +

      + ...so that you quickly grasp its core concepts and + characteristics. +

      +
      +
      +
      +

      + Syntax: mostly similar to C++ +

      +
      +              fn
      +                bar(num_cats:
      +                u32)
      +                ->
      +                usize {
      +                let
      +                a: &str
      +                = "Ann has ";
      +                // <-- think of char*
      +
      +                let
      +                mut b:
      +                String =
      +                String::from(a);
      +                // <-- think of std::string
      +                b += num_cats.to_string(); b += " cats";
      +                b.push('.');
      +
      +                println!("{}", &b); return b.len();
      +
      +                // <-- b is dropped (deallocated) here - RAII mechanism
      +                  employed.
      +                }
      +              
      +            
      +
      +
      +
      +

      Syntax: C/C++/ML/...

      +

      + C/C++: Code blocks with braces, lines end with + semicolons, main function begins every program, + modules/associated functions :: notation (e.g. + std::thread::spawn)... +

      +

      + ML: Match statement, code blocks evaluated as + expressions. +

      +
      +
      +
      +

      + Inspired by functional languages (ML, Haskell) +

      +
      +
      +
      +

      + Variables are not mutable by default +

      +
      +              fn
      +                variables_non_mut_by_default() { let
      +                cant_mutate_me =
      +                5;
      +                // <-- variable `const` by default
      +                // cant_mutate_me = 3; <-- compile error
      +                let
      +                mut can_mutate_me =
      +                5; can_mutate_me +=
      +                1; }
      +              
      +            
      +
      +
      +
      +

      + Blocks' last statement can be evaluated as an expression +

      +
      +              fn
      +                blocks_are_expressions(flag: bool)
      +                ->
      +                i32 {
      +                let
      +                x =
      +                if flag {
      +                42
      +                // <-- mind lack of semicolon
      +                } else {
      +                let
      +                init = -37; (init + 17) * (init -
      +                3)
      +                // <-- the last statement can be returned
      +                }; x
      +                // <-- same about functions - their body is a block,
      +                  too.
      +                }
      +              
      +            
      +
      +
      +
      +

      + Enum types, pattern matching +

      +
      +              enum
      +                Animal { Cat { tail_len:
      +                usize }, Fish, }
      +
      +                fn
      +                pattern_matching(animal: Animal) { let
      +                tail_len =
      +                match animal { Cat { tail_len
      +                } => tail_len, Fish => 0,
      +                }; }
      +              
      +            
      +
      +
      +
      +

      Functional iterators

      +
      +              let
      +                peers:
      +                Vec<Peer> = initial_peers
      +                .iter()
      +                .enumerate()
      +                .map(|(id,
      +                endpoint)| { let
      +                token =
      +                get_token(endpoint); Peer { address: endpoint.address(), tokens:
      +                vec![Token::new(token as
      +                i64)], datacenter:
      +                None, rack:
      +                None, host_id: Uuid::new_v4(), } }) .collect();
      +              
      +            
      +
      +
      +
      +

      + What Rust lacks (on purpose) +

      +
      +
      +
      +

      Classes, inheritance?

      +
      +              class
      +                Vehicle {
      +                float
      +                  estimate_cost(float route_len) = 0; };
      +                class
      +                Car: Vehicle {
      +                int engine_size_cm3; };
      +                class
      +                Bike: Vehicle {
      +                int rider_stamina; };
      +
      +                float
      +                  Car::estimate_cost(float route_len) { engine_size_cm3 * CAR_COST_COEFFICIENT * route_len }
      +
      +                float
      +                  Bike::estimate_cost(float route_len) { /* */ }
      +              
      +            
      +
      +
      +
      +

      + Classes, inheritance. Structs, traits, composition. +

      +
      +              struct
      +                Car { engine_size_cm3:
      +                i32 };
      +                struct
      +                Bike { rider_stamina:
      +                i32 };
      +
      +                trait
      +                Travel {
      +                fn
      +                estimate_cost(&self, route_len:
      +                f32)
      +                ->
      +                f32; }
      +
      +                impl
      +                Travel
      +                for
      +                Car {
      +                fn
      +                estimate_cost(&self, route_len:
      +                f32)
      +                ->
      +                f32 {
      +                self.engine_size_cm3 *
      +                CAR_COST_COEFFICIENT * route_len } }
      +
      +                impl
      +                Travel
      +                for
      +                Bike {
      +                /* */ }
      +              
      +            
      +
      +
      +
      +

      Null value?

      +
      +              public
      +                void
      +                doSomething(SomeObject obj) {
      +                obj.some_method();
      +                // BOOOM! NullPointerException!
      +
      +                if obj !=
      +                null { obj.some_method();
      +                // Whew, we are safe now. We checked this.
      +                }
      +
      +                /* A lot of code later */
      +
      +                // Have I checked `obj` for not being null? Yeah, for
      +                  sure.
      +                obj.some_method();
      +                // BOOOM! NullPointerException!
      +                }
      +              
      +            
      +
      +
      +
      +

      + Null value. Lack of value represented as an Option enum. +

      +
      +              fn
      +                this_returns_something_or_nothing(password: &str)
      +                ->
      +                Result<i32, String> {
      +                if password ==
      +                "Rust rulez!" {
      +                Ok(42) } else {
      +                Err("You still have to learn a lot...") } }
      +
      +                fn
      +                main() {
      +                match
      +                this_can_fail_or_succeed("Rust is hard...")
      +                { Ok(code)
      +                => println!("Success! Code: {}", code),
      +                Err(msg)
      +                => println!("Oops... {}", msg), }; }
      +              
      +            
      +
      +
      +
      +

      Exceptions?

      +
      +              void
      +                  some_critical_operation(data: VeryFragile) {
      +                // We have to be extremely careful not to interrupt
      +                  this.
      +                // Else we will end up with an invalid state!
      +
      +                int
      +                const res =
      +                some_innocent_procedure(data);
      +                // BOOOM! Exception thrown.
      +
      +                finalise_critical_operation(res); }
      +
      +                fn main() {
      +                match this_can_fail_or_succeed("Rust is hard...") { Ok(code) =>
      +                println!("Success! Code: {}", code), Err(msg) =>
      +                println!("Oops... {}", msg), }; }
      +              
      +            
      +
      +
      +
      +

      + Exceptions. Errors propagated explicitly as enums. +

      +
      +              fn
      +                this_can_fail_or_succeed(password: &str)
      +                ->
      +                Result<i32, String> {
      +                if password ==
      +                "Rust rulez!" {
      +                Ok(42) } else {
      +                Err("You still have to learn a lot...") } }
      +
      +                fn
      +                main() {
      +                match
      +                this_can_fail_or_succeed("Rust is hard...")
      +                { Ok(code)
      +                => println!("Success! Code: {}", code),
      +                Err(msg)
      +                => println!("Oops... {}", msg), }; }
      +              
      +            
      +
      +
      +
      +

      + Exceptions. Errors propagated explicitly as enums. +

      +
      +              fn
      +                deserialize( typ:
      +                &'frame ColumnType, v:
      +                Option<FrameSlice<'frame>>, ) ->
      +                Result<CqlType,
      +                DeserializationError> {
      +                let
      +                mut val =
      +                ensure_not_null_slice::<CqlType>(typ, v)?;
      +                let
      +                cql =
      +                deser_cql_value(typ, &mut val) .map_err(deser_error_replace_rust_name::<CqlType>)?;
      +                Ok(cql) }
      +              
      +            
      +
      +
      +
      +

      + Unique feature of Rust - the borrow checker +

      +
      +
      +
      +

      Dangling references?

      +
      +              int
      +                  const&
      +                  bar() { int n =
      +                10;
      +                return n; }
      +
      +                int
      +                  main() { int
      +                const& i =
      +                bar();
      +                // i is a dangling reference to an invalidated stack
      +                  frame...
      +                std::cout << i << std::endl;
      +                // May result in segmentation fault.
      +                return
      +                0; }
      +              
      +            
      +
      +
      +
      +

      + Dangling references Lifetimes! +

      +
      +              // This function does not compile! Reference can't
      +                  borrow from nowhere.
      +                fn
      +                bar()
      +                -> &i32
      +                { let
      +                n =
      +                10; &n }
      +              
      +            
      +
      +
      +
      +

      + Dangling references Lifetimes! +

      +
      +              fn
      +                main() {
      +                let
      +                v =
      +                vec![1, 2,
      +                3];
      +                let
      +                v_ref = &v;
      +                std::mem::drop(v);
      +
      +                // This does not compile! `v` has been dropped,
      +                // so references to it are no longer valid.
      +                let
      +                n = v_ref[1]; }
      +              
      +            
      +
      +
      +
      +

      + Move semantics by default (& more lifetimes!). +

      +
      +              fn
      +                main() {
      +                let
      +                mut x =
      +                vec![1, 2,
      +                3];
      +                let
      +                y = x;
      +                // x's contents are moved into y.
      +                // No heap allocation involved, O(1).
      +
      +                // This does not compile! `x`'s contents has been moved
      +                  out,
      +                // so it is no longer valid (alive).
      +                // let n = x[0];
      +
      +                x = vec![0, 0];
      +                // Now x is valid (alive) again.
      +                let
      +                n = x[0]; }
      +              
      +            
      +
      +
      +
      +

      Data races?

      +
      +              void
      +                  thread1(shared_data: &Data) { while
      +                true { shared_data.write(next_int()); } }
      +
      +                void
      +                  thread2(shared_data: const&
      +                    Data) { while
      +                true { std::cout <<
      +                shared_data.read() <<
      +                std::endl; } }
      +
      +                int
      +                  main() { Data shared_data;
      +
      +                // The threads race with each other!
      +                // A write is concurrent to another memory access (read or
      +                  write)!
      +                std::thread t1{shared_data}; std::thread t2{shared_data}; }
      +              
      +            
      +
      +
      +
      +

      + Data races Aliasing XOR mutability +

      +
      +              fn
      +                thread1(shared_data:
      +                &mut Data) {
      +                loop { shared_data.write(next_int()); } } fn
      +                thread2(shared_data:
      +                &Data) { loop {
      +                println!("{}", shared_data.read()); } } fn
      +                main() {
      +                let
      +                mut shared_data = Data::new(); std::thread::scope(|s| { let
      +                t1 = s.spawn(|| {
      +                thread1(&mut shared_data); });
      +                let
      +                t2 = s.spawn(|| {
      +                thread2(&shared_data);
      +                // Compiler yells:
      +                // "cannot borrow `shared_data` as immutable because it
      +                  is also borrowed as mutable"
      +                }); }); }
      +              
      +            
      +
      +
      +
      +

      Rust

      +

      + A language empowering everyone to build reliable and efficient + software. +

      +
      +
      +
      +
      + + + diff --git a/lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.pdf b/lessons/01-introduction/a_taste_of_rust-introductory_slides/A_taste_of_Rust.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b3167127a6704b8023bf984db44ccbf5a4143f GIT binary patch literal 52282 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�WsQk`Kp6ZDwm+x9@;`b6>1STeQlXU|tdagjG zMJJUrBXlPx;Ue(K^QoT}B1t<<2`<(BH>fA2Pq-4^XdJ{@ZH)U;B`3 zENuVLhWv+3gTsN~bNzE}6r?J%?c|48$;ITWbJOSRU&TPfslWe5&^&XkvY8%ox9%iW zdE`*3jAACyJk#Une-YfAgWdgdaK}nk?>x$(kyq`@SF z9Ju%UGrfDgTOkR{k8n%%^;~yzuJc3>HbRL^L)y!7&nUDAc6M;Z+B|w|qn*e{XdfN0 ziqJl28i<3Gy1Z%QPFnGzeJhQ}UV1y3351Tz@s;sf_xxu$2h{1V{+q*ooFQzM?zr9$ zrx!4>H|+B}h%+F;X5#%z>;)`cC4{}iSQ9P8Nr@y<({UEmfrVIqmLSSd4b_??TUtqz znJtVNzYWMnn}9-Vq21mi$Y0-jgCjMI2&uorIdZNYiBzD$8SB;oJIoCuOHiWd;KEFv zWzbd63JOP>iF9f-sHKrp89Mg$PYDSexS}S}5QW(Mp4ou|t^^M`T@6u3yawgKF$#3$ zFh5ysp_!O;I!WpPG!Sc8BTJWf?c~LLxvk`AP#P!B)z@XbHJ(I|`I-4h`;xmI?=>^9G2`=t1N5NI^`}5RrpMUEHOH@bR`LXi3gh_=aOl6w zY2%Ij63~UN8La%!`LFi@$k=t~DbEtJwq2@te>fNJv~8~=ARSCBt}ah^zO^Uok>%WE z+EUP;hmwIiP@t2?AJ&g!Zp?$wG@JAa`MNB1%m{SqHvJr$IC^Q~5{{)EE}O{s_d%&* zmW<-^z3KJt*&sKTF=gt)YTh|J(BUUwc~|Ozi)$e0u)zHc0$4 zTs=7sQ9fHkhk#BcdiCfD`~$3UT?f6JPyL>7@OmK^J%AXr&BRVVIV9{2$vz((@7p+~ab7N#`d2q5g_#D9m}!Mv+;Vvc93NM3-?E1O z!3s`W@P1u#;gur4!3fKXYZ)pd0dy6m=V-4?p_S|Y>NLbPSy{($&qVh4{P2&f40m(7J{xDv8UI z3g%->SkP8Uwdk|^HKYxi5Ot6xq86%2xC-ILWh864SD;EjDk~XwmZ;a8qX?`9ADRxQ z`};^P(8`-pSv4_@%uOuu4k_o)h`_j(yvxDj=aGlcMgb=gz>zrETr(NuA&^>)Hsl(| zU^r4p!6Oruas1>1fwWvFG|i4F+&wx^R3W=xXPM?MT7I(A7D~8MML!kNJwYl-G@zL9 z8c|~{GJ68x;xAo>54hRudn5$lX^dq|*yd`lZZtUCscq79et%z(J^#P$&P$p!Fwh!- zW~h$(*$V>FHg+7yy7$wNvDwfy2+dUL;m%{eE78C8nqv_^B&1X1*JznuBYCX0c+mI# zb813T#+3Ye8Zn+=q6L2qB5zG0g2SJ-+tT13KYa^Rp9sW;r@cJshd{t{QzZV=1>B`!!$4p~7A z!e~o%HEGdP4@+=Iha4yFCA_{seQjbw>X6#wGj1H|Z!&(-U_3FfhD&6(ghPc(e4Rlm z^uE4o2)Ufqf6PDZWx6N*vM(cd-$IO2I zLdz>-@!DF+#5gMx-hw<0)2!C0`V0MnROxa+mBlLCmFgOBJMJ0O>L3T(@6hA)`02I7 zNzonez8?R=`R_>Uddw@;bir+g$p&Mitm(S^Cu;8X(w>I=mc?JUVm;=Ak&5KF#oE@Zq5fX=+_spQs@Vpx1505u|iqRL||F-7;_g)Lz zf7(BL)YmPE#s0nMf6~S^cJ&~}bqB}nf!_VLOFsmzA4kPZTEkBys07yi9H zd7CEzTBuf_{JigW4?63JRu4SQ7%Ynr)gLI5D4TDv^kW+LK+HD={0aJVI!vZgQ-NF< zl6b79*4z?NXzj`h9oKiOMd)-ZgWzQkB4mX=l2$`hGX7#wY7@!tKTzqmOT?=4XNUWp zD@P*y9l5b+3+T-S&Aj-i()uA9o5gNfLF920o$%p-lhPc5+Ukwt**+{$8dgWti4gHf_Afzpv)b!_T*andSw%U zkb_mbGZG{~`|)a7qhwS5!dgO(Bnd?smrj%p$2smF<$thFGFWnCe}tBU&oWKv*I3pX z293q~fq6L|)S%O;x4;dG-um2J3P}Ra-e2thD$GsoeqRp! zU3K1eIQ+xj!fg=yNk9FON9hzE29?7xFyT&7aJ-=ws}=;K5o19x%t6Yf)ph)#ZKaSW zwEg)*L4cT3J$_;Lw!@afGRa7bM`cpd9fL?q*H^r73^ zhD!(!Ndjwh&{@}uT+&c4p*P^K<`vxG|HZ001VKYp5akNe(#U_*zXa4Atw?`|RN#xi z$Rc+=DD6W9j9H|p)I`TgVEse>nrVVUnG$bKwrrOiBF*~rl0019^C+wMseyuji=hi1 zFXE3`J)O;scF=DlL*CNm6o*7QEgqe}<~pzW(l$QuD7ejOgjcW8kvlGKs`y2ky8-Xe z^w4}+)9c-Pk~gRQ^=xhs3M?s1ndv@_e|&7AUi@nn7HL`|9cL@*qvreuwc@Ggn017H zYZ8hX#@jbY0*sK;5j^cmzZz+@{Tp?Eqr-*PZPyl$u9FTP^u1b-V{FZF+J>f!*hjZZ zNKv}Own=uA_Pz(*ZL$_t&~=bo%d(|GX{$ul%q#C%=h~`DM6atu_I1sT-D&8`$|S+J z&iv2R5(Gb{TBjeA8grv5Olgb~lR~V%zWb(c^Qoo!5Aqr&{cw zw1!?x_j8;L(>FQ_wjGTCAbk&0or~CXx^bhy9d%sbBKbH0i~L#GUhWa+*s1K~f%B`g z)jc(JeGZe3??rtQuJ9;)W<55!Yi7OYis-z$t{X8NC!1bfHT}s5yA4MhYI@#K>n;;p zYu7rDQl$e8t5*l&&!ZQ;p)sP{ysPnj}LklQ1;rDOApmNmFsmTim1cH^W zot+##aK^*;i~iX7`TfnKz{LH(44eO|@~vJNKUhB|l%v8!HJD!G^d|VC=K9q0TDxHd zB)#G8dGn(KUJq}7C#SVdwwM09%two%LWPhwp0|yIKMGEK6*?l9{}DH?2sTTh#M^g@ z?{|k6&-!7ia*i*Ia^ZC8fgf?B|HCHy)R(!x9YjH3P)~U^!Z*n#Y;_Mr?QTcf3QCLf zuZbL;Q$7kD2uh=@c2Y?Z4eZn$n8s2HD4@eef)F9skM4C4E`0u@b{S~t_XA(*MPoRQ z3(dS7@qz9nLU>aATIHD5`sjt@yf%5VA>2JM|5Wo-x-jAgNb^jFQc*aq<}10uF&OGG z(E-SU2VBCf;m#N~gg^FiGJw_+d(VOM`$~5?|5|W{Az(aG`VD+k<=oc`W5CFOtxW!9E550KgyspSpSZX4hrJ?AGXu?Kw>ajc|cDQQwOZW)SCmRB#QP~EW{Nbz>C)l#@5?N5)i zgqD2XnT`A?ycq~?voXweA(RVLE#!U_fT9;q2?yg|E6Mpkjez>t( zu*3Qx*IPs&@I=|jb-jZ~vu74>s0WPVGJ@(I`DE}sTz)1spbr4QYJIupt+PCxXG#`5Qg8b~r!kHV7X zRn8dU4f3*tcK0R=V-Yd6+{sfpW+d=J4(hBAtBJyfbgmkq$-?SS)G~N62&PY|TI~WA zX_mf&EET$c4ci=SY8=i7G-L8$65N(AhOy)|c=621+a)KkAfRV$0#-wB8>1tXyJSxaD}$G@i*3)G*1IXCfo-z@S zeaWf&Z-Vl_HVhe=*!~k_F!U3b+4z5h)%;{myEi}}pxsZkd0AK|;KefjKy>jxd6~ds z5=C7rT91wj*qY{I_GgalU7&wU3jB<>O4QN#{f!R-!4kJ#UN1NNPh93$ObO4|8=IFm z^7ZLD{wM+%YueoRgT))y7yD;6^^d09-{AM9`{|Z^{T3Z+Q;!Gpnli;NngG84^UtGn zRkKO|&fGFO^|=y)i<#m8&nM2v|B)=URt6g9LwLBignUei(w zi5@T%2v4L*eo;Zw@Q+nM&+JOgOx1?ZQm&s)G!eErc?=0&)-ZfBu`2>n(=36lT?$S_ zBJ@N!y9QaCjGG-hsKz&WPoGf!0m)fPT0ge|B2}dws@gy#DFzX?ZrWb zp(n4fksr$GZ+yYNPB=>PBG#SyOz|EJa7VcSwDGbXeT26M-aqFe<$oxrpz>2-)MSUo z;h~pN#sr}xOVL}a5oZ+nZG$H8>TufmKQsNJ z7u6kPB4{E$0>?eaIB{~}+huA2tN`E^&30lUeCY8(OH(gF=Y5{II5(bRfkFH9mhFoU zmWF>Irs7!CAi}=~TZ7Kk^)2>`0nQW|-Kh3+$z#)qCzPbDd*3vMkn^oD8^jK}ZaJO9 z!D10Upk-Ps<;?XKzdzPcb=;PZlk&tq0@wltKP2VdSH%tBhCBD(l&P9K)|#G6`(;=kHc+t= zmRmz+oV0dA-nZN6wc%^JkwiZmS{yr3+v!|ZtpVe*W*%)Ui%^(&c$wufM%wQVJuV#R zW{k2t+a+rNxg%m>+S5DvmJk}{roiacqkj$v@y!n`t26-uo>u^C(*DJ@hXuFat7XZ! zATdaq*EEe?!1dsu$CSY#(@(%%`Pz^dL|3N$baY$QYk3lGbk9|P4Pa>3#U2*o63XiJ zf4zFcgO!NBALrX2CMT3Dt!`r!s+5@BpxWCE=5?illD7(iB^R+E?76GDvbskoLG0+( zuSKik$}7!7iU}r|NWc6!uTic9eX#fGTvdveiB>~4RYb;edCWbQ7?Rdf<6yHs|^70qGeN=sO?PoHvJ={Qb@8*Y5 z9T057&KDr|EdwSh1xRNrFHtI$mbtoYes^KnI_wT`-_!x0|Apd?U|@3sb%Y?jL-;mH+94~ z#>&(e6mvU>78<#Iu=7*elpWh!r}ZF6gh#97zRb}iXuSan#)#BBYr~h~Ivls}{g$&e z<&-7NfI~jJi%y_c`JGB@S>Jo*G)+%OdNjyIqbHR8Z+bQYQLAE9e+CK zZpA?uk&Cn3g2V}ePuXnJQ9p&H&#U@=9v=7pzG0VzlXcWrqD_viz^jU>1h|^rYsf{5z?$tTy39IHv6qATKVn zf1DZO%fAK!L`U-JN3r#&s@Y{!XBCv-GLxO*^khyfh0EvfZ;#&9R|+xxeuGDXv>x8J zc+ZP~)7wQW9Tm51--qh{i3`W>An-T(=9Z~D*lyQnLq!X^9=F$Ra7&Q&WNEp6l_?rk={;Pax@zHuI-4`%mEf)EmhK7dRN;unxar~y76!VvGD z8#HC2iiBSTFnl|JvttnAu^mJSECewCY3fXdDPRYPFPszI!?Us(8gmI5E=1)GR8a?g zF7l%O6p{uqxGlUg;*rwT11*F~jJ31OQnvoHgMy5UnvQDc4tT^ysgAraKPdD+v?V6I z3ib+?9EP%oZ-{?J%TX59w`czvUik$ew+rHVgbVEW^o2}-B2Do$oPC9Nrgc3v* zb(N_+YA=(R*`%b`q|P-raz2j_B%TZlC^rLQmnBmdvTbvYzrV(I7{pe$95|-D2Pz*q zYh~M_f0f9_n=E*mxyVd_9z&Z_a-6x8&=q^{6WOw&M^+nYnCM z14UbFN~i+#Mvrvy3}rVjsEBP;b3i)aKSM)uw3a9|FMa78kQg(1Qd%`0=|)0Zy_a@( z4XOm2%TDbMeS@15oQC|Dy`J^|EFS(%wPz$?WMltHcK!d7?>RV_|8wiF@rHE9K6bhK zOvAJW5x*ed2LgrxNL&#Q;2JU+l*uAhh%!lRG*K)x9&JUlYM@+|P+oVzU6bf$j@>7* zJ!?L#&`V@$o*$gDdhZ@ux0o-Uysz+FW1oD|#%G&tNK#Wn3#)T81qehbVLs;GlV?ir zc%J&+{+@Dc%L4)epkoJzDQ&&9rpxtt?_vUIh5{&k!q4E9-8SO@@T3OdZvTE#N_>=l z!2!So_aFGZ&xXsv=phJLzX3(?^-+47Gy<3p2CxMTa4yr9%klDipuh&8RtF%bC=5<| z8shh}9T34YF#iwv1-#U1NgWEH7#1KgEH*py^U!F~53;`(l3#Yy)B5}2dH2!+;EfRA z<1pcLb>Fz{kPYC*3LrjK7M~;D&-l+WV6Z3vr}xLos8W<(a2h~3{53wG!_JEuZ5}L8 zJUW0r69Pe0lsqi^G4_saeZTGwKOvyU$yZ$hAITRE1%iJ5H;pfzNzI)Q0L}KCEAYxN z8aX;sYdKxR-EkOv}=p&w=m#Y|qH!{(49py{x5Py$J2gCfGv!S2t>Py`EwOH%)~!Z|$2XiG)oy zC&i==SMA(Fv!v+L_`5O{Jl{`4Hq&QGA?UjkINFpvcQ!rc4RZy zL|(%W5nFr)oj`c@2_Sw9OaB1ey%~_n8DL-rC~O1li(m(K7&A0<7f6f0XU|K&!P>!G z`&$@b+i2+MzMLPYO{y9{j`O17PpN#&qqoHIi|ppuGWP zZ>Vo|Z}n)bXxucfnm?LU7Wk}c{LIdqeL(r1=-%Nk`0O9pc~uT;-wwv&?lsjW9+e+& z&xSJj+~_^=?mohf`MTvir{D1&*A+Gb_l0xbIQO*ioaw)ya-a0FdDf&V=Myfbj#3=VhZeEe|VHFVui zqq}Tz%@SJ;Zo29K!2pT$^S~}wKb(I5+uDP}+nO6x~ay z$CN&d>4cN60C9i1!RH1T5rM1@@Vq@#tNrS>|kZPAQxf4_E1yl%JcRp zraM^dux1!<4kx70#>br0u|Pe<*#nxSVV9Wo?%! zNiY^$!sND~=Iue?{6Qk_%#r114)K>*oRyD7YUkgQ6k>~|L~C>E5o-Y4F|lRgmp_e7Kz|13%SdIzThhMW}X}tet4d>YKQ&#K<0DECMMVM4 zI&5GWo9rwt`nt5T=L%sw@6u3&KKdjz9u8C>D!B^ol5G`&6-$H`vP%(%vy>_riqn@_f?dC8GGS#V z|5D*+=3-*2tX5R>(Y0B<(Y1jwWz#AVeA>OXy#I z{FLI1H#VvWXvW)Vq*-^Q7d~C3YIbMIT-M3tp)ysGdr`SBd8};bDx2sz%W%}GTA&b85NJ7mv}nAVDS4(Q zp_=Mh61ZU^8FhSA!_D&2rM3CCJvn0^{&M#;rjy`4R5(ID5g^Xd49=1|Sp}KxWzk8Q zZL7_CY!%zZ{Rd;pUN{wM?j)OACsSES_Av#Nc@Lc>d9q68O~Zz@&eVD6rO}c-ORb4x zQLl7r7d?lwE|1VffKO=dC>x6+sdWcE$2rC~v{>X5MncQUvR-;ERL^b-;s08ty?GWMoUVrFA*YD221< z4tJIW?77eG9$H#*ZDmu(quRVq{zMDbm5e@W85e zo-(bx*~z~e!pYCi;SW6z+~rzZS=W)%yc`KHF|R&Pw%h8B((sOsHNmjha4xQK&PPd* zzee|Ab2K<|qCkyY%Xm8KDYtSULw;>K-2eUF*=uF|4U3|y=bgt2b*~@f*{ zS05m=15}G#$!=)uDQ)8Hfy2j-`xj5{(o;&g>rUv;g7oE*zyz zaB16W_|;6c^Xer>fM}sQM_EFOWTBvFQNlqqLEr88sdusYj=ns<6?IMe4xJ!gz?XqT z5&S0vaDoat3O(2kihcmVI`kO@KVWwE$eWW=q$5a0@fVHlDGbihLeM!4Z4B+aJgx{n@Ani41%I#4XW8qvhw#W$*e zZ?jXFF1(x{Oq*Zev=N4Tkhaq$!7v$&mX3%V3ksxW>^f?W;FLV))0p-)0u4zH#hghX z63E8xyetPa5d0`=Zpl!L+yU|JqM@5k-F+DSf_luRapXvDF-Zt|girr6g>%UkSZNI{Z_O>YxH_lnOSjgo|TZ7nhO zc~sc8YKth#=cg?mO>&+_d-Zp#0;(N6oQ)Z;i&3ATHvARL^_QKUC2+WBzXyTwrP_3w zgwNNk+1}X3_rE#=+$#oMfvb7A7er>H*f1+Mpri`(D3qB*;xvWgN3fBq;sD0oA>#qt zsnK%Fs+}3_qdG3Ff?mCgy5tj9d>)NOU0wSUg9I4!xg~@R5J>7MS8fPmsrjnFzIp00 zP}0kW43ZzbvwMaIZ~DGENz@k^>+a?ZXxQA%4pX?T>P(V!{Bjq5pC!kxi(!HaBP+LV zzK^>dPWWGEIqSnXv-!l@P4};9+x-cYYfTGOXa#V2s)vNJ)onHW*!CHmVB-DzwFPLO zT4sD*D1Rw2t4J?$yJYZQ0~JcTdT<-*He+&>5I!D7%swZ(4P~lt}m9EAd)O3TBlA@+O7qk_7itV&1_@j@x z{;giPust3VCWN}H&R)M_Xa zOaPl?P>2MJu>?toim@0eyy+*_`RBRCjTFK6^w$M()HRK71m%E-J-;p@F6;ej+VF4+ z6^4%UNxO}>XcV71Z zF91DrKW-#X27exbW2~HbOboTbi~=uYa;M?A>6lDD3?L{N#Mi0Gvxabl+Lopaxwj!p zNxPbNo<>FSb}93lTa|nK!`{1f+6@u2ApJ&FdnZ@cJ#0nr!DF~KO^wO@SwTR+YrYWg zu@r+{1O;v%3kf1f>^ZC_tTw2SvG*7kg!ax;q zzAcfp6#h4n4DhlL{l_VlmT6662FRdLhwKGgQtZSEJN*90`4;*Uh=2a(Lpjg$ms>DL zV3^q?pOlV4?s66rC?P@M?HLMFD#sV@L4*(iG}lh)w-1vAQs9fV$0e~xGyz%IBSzgs zx-u?buJqh2*?P%|zQ?yFNL&isoxW!`c9AJ;l2~Z!=%)8MqrXbOm2UM4SyZb}1Kr?5 z-|qymqwMgK?mPpdIF1JMU8M;E-UOr}T3I}GPz|t8Z3$u=cKSdES`d3K1hdj1308)a zh$gEh;qdR|hb5s#CnGRL|H`<*Kz9hNxpIdDpT+DbpV+7w@?G0f&36%0%8 z-)0oHTjI?+!AQkU(LNz(i7C3YA;yFklytle+(Fb0CgLu1hdB5JNvU{V(GV$5A|fRL zZ38$!NiLkT%0#Tlp)RY_J8kQ2w zQ24-+D5Lb!CO6jDibI&{Mlm>e?DT@%+eziG!*=@C zpF}b{g0L7aIYy~4223W2HD&&-Lc;jZmi-qPPe9Lp6DqhYw!89keID9wF1AeKW|4SJ ztqYEi_cJL^n$NdAD%Vf(eR5nZ__c`MqVILCW}Cg~YR=_+${TnYjh2USA_!PkhfuQL zp=_c6^Cy|(QWw`KDW{IbKx=`HAb5j5 zB92&W+}{rln>=GetcA7wo+GY2xr_YKvAbMU<)Fgrf{Jk&O!^#M}hdQuypbqnb2;oQz|YV zcd(>K&ol9b*Z>b}H!iu-SUWQ0W09_`=OU#L5#FeiPc%+O0+Ho7oDn!e%9gSTD&;Dd zfoKU>Kr~uhKAghJ*-+SS4702nqTSrsM7bMrMzGAgqOIGSm~GqppId-}HLb!Y2RS{Vf`aLy&7qDbw1NQl6+3db8S*)<#*Q4= zhY{Vr9Nmp!(f1{K_d{dF(!OM|GkPDf^fK2zw}RdQSs{ih<&Z$YzN#?;a;dGZ%%asI zLyDS0Bo)$*&mfJ}J$n8s9JP>`*uaU(Hi5T7kBbCzRqJYs@#Yx_5S^7u9u zU0&|rB~QF|W01+W2w3EJB`kIM9PV5$2hwam->M5Id_R|n_405r(my%Vw}g<63eXa7 zXbK&EDWHdHLcDSh{9<;^xD6G@NZyNS)M6wQWl(F-M>sd1gFDfPKy*4;go-Xs$1`W( zHoRCgl`Mm~9fIic#m>^mW}sb#Q3xc-HP;7KjFg$v5Zqem75F+GZR0B`X2aLWQ^zL2 zU3;#T>CsEFS@HS)>+H8Va@CP1isnl!mA(KH@}Z$~vVHKCL#x!b zcYdhZ-Cq@qUI33bxYEN&JMxDxD`fuHUF#Dfk#IvV1}H%^05#Bl@GaVm5M=b~a3(ayF*--VhxbB5N@cqfX34;sq1dO^z!h83JAo(i z#asJ&pC15u44d;MhtJbPZtd*0-)rrz+@=>5*SE(Wnq^RXd?`}X4SFgKk zQC|gigSqK#V7)+FjT{9X5N}=87?B`t1#OXk-l+($ZE~@6PBM;)^hiHzu&8FBXpm$W zFrI?(f*Ll1zFIMrfB>He2183xo+zb{)k~@jtnrA8T+jUt@ili#)`j_sGql5jTh8i$ zZTG{-^XE&&=xCX*H-6XcoRZd*b{5-{Cj>p@{Z0T+h^(c(RW-~>Ror3Km5 z9W9g%zeTDDN+0SUYi&n!V8ICA&A+0Xw}u4jp>}hT6(TaVRgu9xu(oPrLV{1ZFt;?^ zWj=E0cF}roF6S3JJJ!@ymE(FFU?6Tx>a+BwJH?7A7Lig7o^4e`PEe(Rs=;{_EDY($ zJnED&OL`tz0@z!_h$FY0W#c0g7TCk8HvQ^LH(a_nJnr##Q7$eb-z7|;c){<%9^w6)kvxj$wXU2Pl*FyuC0fxP z`la|(rv$yu^9q>}@{1UYx&_~|dJgZ*eM|==+Y>a_ zx;u*g<^fnWv-n~(_&VMFU%C5VrLHr{_N+qr9q|^^t>nm$3G)5t4O#^e%&Sr^XS@*% zgmS{rr>2IiQX3V9VrE@Y zuRegR+2d;9Sgh6^wLYH}mmReoZh5QRa~x}{smXU!wLN@&X4l7XZWgs$qXV!_MG3j` zom{%fn-#Ea(XP3j3cDRV>q4{gH0(W2UfT&HWN4<}RP!GQ@TAZQPt{jO==3+610Lle zI1W?+;ut;F?C7Hfc`j;NAd+J}K`hbsL__8MpTSTtOs-}Vg6wRlM}LgbVx)|f#iVAn z!=9i-Td9h|>pUWQ4t%4jbR9^U8W89Zh+&6;r~{JCk02=04fYnjSja>lH!y`2J;^1f zhk!%NO+9|=TRj9`kD9{80lI4HINXIpqpLY zI7xClXu@7ADzL7z_uXB*N|@zyKQt=S^Dz!1*9~u$AY3|vDG^)?4OKV1zqrC35rg^o z(W$S@Wg)O04VG_QLYLcwr*&C@hWgXV#(cZ8Eku;{S!t&cHnsjciYTWz}g zJ%bRok$8Ildpp`;DwvKI42VWdHFgwf)Hmo&F0KJ`cxRXcMHk9zWMLQ;zB?~()o)QJEura-sCgp zP#fKhEC35|C?GK{DPnry9+i_pGiqQpGvTg5oI;v@m{AeK!GqL@#dr|(eq6V*`u2TY z%dm!qH!v#-)@~a)uFML@H@T-c-0>th8EI#R# zW*1%SmjtF{n1o|z=$@r|`AD=e5nXtRzkl{6DRPKr7ShMc?p+M>%GOTn1rkYY#;FX{ zdq~W!MGyiQ2LCjtV7Lfazw6l6TBS8J0->HPfr{WdZ6*!Qi5pOs!g`0UmiXk~MXNeRn0Yckc&(LU4 zKRIERLTDF|Dc3eBicnU*d1z1aYEeo(70HnmMI7IPcC{F^<*M+pc#*!VkCVm>|Frio z!spbbQM?iu(JUzu_Tx=w>9CP(&um$i+qr(+^jkY-n{tU6wx#xUw}kCx)4@V-M-?x~ zb_K{QymG;2U2URhMy3UyFW~netal8`-6(edb z0+gajo*2e)cMF`EFU!F9P(6R+0c;9byHSL7zm?bIz;X`*f(Tg^U7HdH`vli$e=Ia* zz~3J=yrsQ!rfO`xYi*~NP7cJHPOwt39#yZ?MlCUjL={>cvbc^Q(WysI4+|HMVUIB> zo1dZfISx3K&F1H48zRr2jAwz*sqVniDN@lgNTbe+;z^9sgUO*wxb=9)SZ&(KMc0jz zagxhT=4M{t^gf4lO-91M%w3z^lokRDI@ zdR{NZ=`4TDepknMR%b)@vNZ7j($-O0=AX7b#a^j5AkdV4om{h4WQX@=33`rM<=Q z3y2q1%{K*{&R^bk`MFM119BdKdqkxcPrr&ENmn>Tt zw(Sl>`5SyfEy3*_vw(`I#p&df?N%T;U;)k%;-ZMCC7QZ)v+<3HSRoL1*-vB{(XBDe z#o$`!=UU+Nu*5bBS05+9S0pYKE>>sf%hggP;EWmAG>dz7=u<*GAIc-|p5=8>!9u!i zn`5b!%8gO_d!5M5>33wvuQMo16M% zV_4*2C`6|51*L_8W<%kq9z`CF8F`ibkxtVYM1nXwC89&EuyCeH>3 zLw>tL-=rE#fg$%KGwVRGJE`h4q>omrn_i~d22s)|pr?O#Vo#5P9ad^^?bV9w_*Q}h z;0OB!TOrJ?iC+8YQF#%)BH3U%N2&-X6YStziSv#k(WAZ_sX+_GaiHnC5BTi+$DYsqHnx1d4flK@#rVyR47)tTK->fMUigp}s!Ovz3t zQLG14j8XT9(=!Z>rDMl*VOY$&F zS0gxV_lUL&r88+*2OenzagNG`=OT(X7i4%4L)N9VatccHcWOsn5RvP|XV{t9bv;l0 z@l@TS){&KDx;pjg5$an)$IANAVtLMPtM6>aO-hLdKwCLGrhDIaA9>3Zp zO})wH%fd`8GB#og*>aZ~{m(jK3fR`j(ZHhQ+lL+UF%HK^_L+mLjR; z=T=&x2v$R58leO~P4uNOcBv7eONX0esZB@?$JmQ9#uFCxf1^Gb6!u|_BdN}*H2f-T z)*CLh3;3q>MwTMLE@A9(w6u1T7>A7Vdg{=hxZb(ClDpQ-vpFEl>mta*J(R8LnquSe zWw>SPTX%gP=;0@*cMo{H_r&P8Twl9d^fUwR>v22k>UMKAsr|<9VZwz@%`|)XtPJOi zw^GSmf@6lg&fVbISa7+ZW^3E-_EU2XV$#4LMGMnR8Y-t|^4>gf`IE5}B=_@)mp7|3 zjbW{QSoiyw$J4j^WZZO|702f-R=q+F#{qPh#gNKBiCjzSdenzvrc3Z!jH_2twH0FH z(lomIg)_jvDt_Z0&vvfmPe=KXS3&$rs41c0J|+krf`oY6n`4dsGpU)bPzNCR2o-Nu zLABf&2+q)q8nX9GSAE!$F~@5fRbAm(*m#fvJE+5J48?z>owSewZXk^jS=wlbC>#hq z1Z^WK7F)TNVgRNXq$iG?e9p(%-?^I9mc~0-vNQn00r9R$rp?9z2cGn+xvuiOLMrW` zo$I8wwQHlbrzdXFxD6M-pg{d0x_PGXb0-WMdek&(a?hD3b2@0Y>wskgvgIa@lWZXn zuV}3rNGmdn2E^WuYo@%vB7?i&`&X94Vf(2gr(_ijO36_kYw~_6siqG&c__SjeaR&- zDIT}}#)2tfzsxE|FH*H#X0$zM>#v={PEO9pOT!&JE54LR|U>_ihD~eL5ch zy{V8QEmxDdhcbMhnI)}loafq}*MiLlM20tOZ(z4foms42>*tu9^!LN@4wDXQ&0Z5* z%;DN{T&I%qRqX}06aQ6I8zN&9vjktM_Yl|Q8TYNXc&;OR@!XN>j+5`hDRp_PtKOEP z{UzJGApMDtJdi<&t3XqC=?cp!a=P;fR@EnAofMwgniU#r?H2ORSB_Ao3fj#@Ataym zAb|icJ}fC6C8JDFaCebqWxKal-5Q(DRDu)M^mnO@bW;3btzaP)-YRNUpEmXIsiCZ) zF6~EIs~Hbv^Vr_9&qq?doJaUeyr`i|_n&)dfZRldG@afjGFjfa{%(UCHRP+B=ULER zU6b%Zi157;D2su5uoK4pg@$gYhoY|jAaE1p*{EANC(gxEQxSP)KB+?sNP8=*P5D&n zxO+n7D#y$@bGt0?d>{4SLSxG;he0iLQ;4&gj+f?Eee6DQ*f>uPESB{O)voJ7wR7gB zZ?BFsLVo1IBIHa1^S+qp|l7Nc$bz7*gSP>z8`8K_g*?{zY2{e54sv#=t zWHE9-bb@lu;8?~us{Wn~_n6+$t4*T8>}npY*zUW47bB9yl9-W~%!+&DV_|IVqeX-| z8js5A=nmxtlA;eju$<_*?`(~8PmEbA6Iy(V--onvIw*V+sLuU>^b&)J7$#L3to0tEkSZqSjZ8Gq$0TSIBhE;76)^7AJ^ z6wx$ek-&$Ybvu3QtP6or@2L@(=;~_vmf74!Ikr(S?#mVhxTDh}k{LKK8*!rYxw$$8 z@9~C~;FQM_4O4g{o41Gqj*<&#FdnbAnMny5Tx-a8d#G$y;7#puQz><)rYCe!hFnKQ z6lDQ9_1C4fXIGH1!qzHOjJnUpuGC4UeXj<7k!a)#QCTR{bxHdgO#g#yC*7Iu%F0Rt z{e`}3pqkn=z8dJ&(UN?Q<98)QB0>g1w@Jwt9nYne5$@b!ksFG8^kC8f;DKcf()I>+ zql`r%LK%cy#KK%WMAa39GYiaJULp5zDKZ2+#63CkL;0(YM-5Ft+{^`K|J75C#_O}2ONGKwX{m9?~NJ#ME zVeS;2aVzn{7L-Gz91XNmbfb;RTVivn)*jS|EeT3hl`@xW8rNj2lRp{fuI|_pbD5EZ zzrQ=Zwr~IhLM1Qr|6X}~`uVwif9ieq0fGQPb3>qzvD#Qj=6v1eec=K$0QL_)?2dAL z;1?tLPXP88oO;QY-|?yS!1#9o5Onxm_3s*S#g+gj`vBa9fs@5e2LM<4ioHt#l(XBP zOnlYA9`gd#TLYNC-2KiN^|^@Sodvj&061ZHw>O=8EB&AcSOEq2e;7N*Am4$8%m2sb z9ouuqwr$(CZR^e*+qP|c=8kRKwszj#s;zyh-rC&{ol5d4=_K8qK7G#51p*<5{nIPJ z5ze0%!Jix+H!J%i4Bzh#8*s-5w8Mv!&CL_Gp6CbUzYXl~X?%Ah?KCp#0Vo6ZH$IBS z(G_dL2bnMB#t|<>a5OTfGgWqzJbO3R?St`Kla^W%> zZ}OJmTtE5hu_HH-58cD|uWY@w*l6-B3)CrTcPU?{Lt7lV4!uo^A zDmKgxzg^kZhy50I3;b zsg4qZkS-v`lyHdAJ{tf@QAg>X4d^7=hB|(AN)B+bhMjVPjq3MkM|c~hBbZ{ePX=Ny ztkBQH7lPZ@MdS~_)uu|r1nAtr6vXHUK1cBa!F&|Wme_~gWOh#HLc?SEKn>^qI~niC zxAm7`2NEL$Y8imV@lUXaB-_QX4#H#yA2C3S?njc(1B;&lo}2-v5(v4Z2N~H7&gB4R zzz8a^hcw+~#{or+?#G$vMPi2++aH}woa_b|(32UGS zH8Vgn)z2|6$%9zHzS}jTFb_pD*IG8hd> zEtZACU;3zrByF%<)xM3*2aDSO63J50bueR1rjF?vAhmk?CeVUB=w2SLMVFei77%-!Ulw!Z1* zk_ulQom7PqBpXNb-+59Fxa7(zYzWaeNGfbrAp4$}->zPwi{p&}x52dcP|nDh^h=I? z(nKKW|HO^?#bS!jm>H9IQK%W|`D&)D651Cq=A1Jpor(4$+%4{ya?sp2HQrT7pK}_C*KHY`xWp^0ngfpHyp%+*f{|7f9uPC2ugIz!{oq^6@~Ts^R3tR~np zoUpYOY^!CeJkobs9c&w;N3auKD&bNk503mpr|MDFs*sUAErru=By87-g4#q{?ki~c zGeu;mJhC$3t*ErP^;#W#MIBu(!BBk`&zfr_y-5BdQNm_MtB_RoCB^*DdmjWOy*vYa z(L)B&%8Ja{Lf+5bGVokQw%~MUkXObmDB*pWkrOxb;oRCj@I3x&XQ8mToHN4Gimc-! z-4;uGV0!S!G%8aHP9<|vN((1zpC+M=$*yWPE1_bBG?gVv_Vn{Y`O+}!9guQsiEV=B=J7c z6ze7r<1hDR%?CyFPH(0y&_qFX9f40 zL`cH%G~ZDFgLV9t3tlH;T>pfjyqsRlh zh2&4M(tbu0Uw=UtSflmKY!v!AW5%64)3N7iHsut45OG}jz;p`sho8%NfO52$r@~Y1 z$=S`twXp~b`>elDvqZ?$MABM$n=4rY0T{U#ARicP2px-LJjq>B#E+QY%g@LV{ybrd znG0{+#tli9(Et8dF|XA0yVTd5I^jw$I|Vnye-Gqn{7 zxyGgHA~#o;=&DE&;;q$$-6eIQAKrG;@~(q>weM15GlZ&p7aY*Lk7@f`7beH6wLQ-uNzD?mDR!gT(s!n|R4f`6#H682rBp#cm7dWcm1+n#Y zPE{j+N6g=k64rL-Cl~hm`@5_4LkaY+J4lXqK{+`b?+rQKew`W) z>e9`3e8Xly269h1_OQNCKr0!^pNovd9z0I!NS_~)!SWD)P)iksY?33@U&YsQy#7E! zY8u3{5t6|-H&n$O$jR-#pIj7VX|hW^tpqvfxT+!vQkC< zLFHjdmQcF^YXLDVN^OgjTLcF%^dH}8(ub~uQQe*=Ppv61>aOBoxmX#T)-2FNT&cgP zGfLG6Ab&Zn1=QyAs%stAX`w>Jrz+od*g6rJppX&(<-%fwBt{Z2#HI%@^s|Zo;em`- zPK+`fC3E>j4I~P+@2bV$u8{P3n$!X=nAjS5ufG+HLTDrnHXEqP9$wfrIjgXoe&>#Q z>+g`@)&X3|vM9#MwGz?%4=!z*_G5Q3LaD(o@Cd!#{(Bi&fcn)$gKu+}z`ow6W7^c>#CdBxwq(X}In5BL>g+L+sl&NW})~-gBu1 z=pd{Roj<5$9@R3pd3e9F@;955NBGiArqli+O&~=m;85UiKUOMXTkj(?r2I%(B}aKq zjL96_vI0_`2kAj4oWz&&FOhzBih{@)6u|iDZ;-!{N7|HO{P2V^$HJKWcKEK)r1e%$ z&C#-nMi|v2fcDGuEGe{8g@}&I38Ov)Dl2a}zlhk%4o-!H(y3&Hx2h5!mZTS?xQew; zmMUJ)mX?cokjkY^ZJ)HAB06JYh87L1P zDHk}{@y&Yv;dkxaxDu%w7)YfEzKGM***HhjN*C$qhf~b1{#KuD^a2 zn<6R@LTg(Oq4{2kCEj?Uk#9}{W4IM1zlprSFl=~RYsBuAXmKzigo4R;Dc%VlXawkmesoUGr{V^?Kfk9jl&4LH$kS_v z_#zxzY%U!6Cyv7e8KI=HURXj$@HWIOG2A}N<6V3ch17{p(~|khaL`USn1q0V=&;kG zs8=Ip=T3F5ky};(d~}Q$N4hOfUK46V-qZFk0IoFB|6@|Lk)71eakzieq}5`KVpZ!h zPFbvkCtOn<4bRc6aboHFEbp>kTbHx;eYQDbRpq}bpQG(*<9;_Fe6%a$37+?3>eDG@ z+D3O%Mlq+_*WH@u%P{w|3tyVAsR8LvZ4#du@`3=c&1tzgsDX$O36jjhi#EJfkwyS# zCDZX`@#FvP@996+olb-i=99PftdkfDUM9dQ| zhECrvTzr6s>>Dd6eY`7x9{}9M;+wN>P$q92_g?I7UPmM#9PR)|9J;g?)Qj=w0=gGD zQ6ZkPFz~eUx8MtVf`34)HjoW~MCk63)am9qf7GstR9@CL37SIBDo$H8T;ei<-_RhP z-$~1$6Kd?s*=>x3-yKqdMg+u!8)3nJ4kwvyFVoSXh&Q~Vmc@*MJ1g2?MbMJr0Dg5l z-RWJ=di8Z@MIJ$@i8U4HvUEuN>H73aa_mx*uj%vIjjdx?r?@;?`ui%Zx*HNjan|i2~2hpeaM1q39y`_h*!F zKC^r%G-COIDnh(;$PuBYyFnmTCr8Omy>)3-SoomLr#e}eEd|r9Ba}?pVcJ&W_SPYq zo0Bgi{S=Afzm-9yei^pC0SRg7RK$EX{V@zVIGBok8D6Hr#1U-Aj>?mOSSkv%I-dDLrkShPoo?i%o;7VYcjH_}SXoTJD~+VoCO5;b+B=%h zUCEZ0V1p-`zv|+c*5h5(=9JLu7#hfvH0J$W?cBVL>wTPAPp~fTm`Sm1qU0{{I2u@9 zSN$T%DyT?S54Km3bTKQQSP){P0-|RJuZYE5$wj$ZXQn`AzDae!*|a6@^%PqBE^Ad( zZ>*K3wg&}iC4(XMIdJ4P#eqphA>v>|W;c=w5~6%Uc**a~w{#>rGx`MkDwuGk%i;$9^wvw08oh$nrP+T%G;9j)`gh zcPx^x;wo_75JUv)L9ii<;Us~WXbOVz9=Jg0<$e?agyd8xpqfJ<%`XxHg~6#ebFssI z1^$WH0@>nJjJt4jNQaHv)vH-xD$}U?^iH=mo0@aSQs%TN$v3a@=^46hnzA+edb=9G z>@wI}j)6|>ipCN7y(BtIj~w&VOOwpevhD3%80(#{I;n#CNg1>Y72>et@3l|^eu0cc7=XCglK0whr4M`jDh%?27-W`DE1+IEg#xWwZ;a>)qq6Ay}*<_PI&=BI#DkQ$Y@~Z&#M3N$qjQfia zy0QAu45>Go9Z;xSf6a|vvX$kPakzC0?rdKO#)<5l%^EA~&%<>f@JbyJ>@uXIHd}Z+ zZg-r$m1Sz%;>JOc)DB{nS$_ zJXw{L(HB0|pVd8#i2F+;HaH}6DF6&;D|T3?(&p_YcQ*`8N#3vB_BPj^T{G@4M$z}) zVcyA7R%bWTy?*{lHB!*gKa$=Waf1DaHTX-%SD1zxoZBJK!i#~;WoKK zcw3w}iF~Uv3>=kiCT_l@alu~sPKQcj2g=Z|Wn~J-&W^t?7$a6b}P+R zd{&zDrp7nY0(<;8ks-RDA&_q8R3?a~B5(mRg(p#vLS6D9^`cclx{03l_#UV2rQc(1 zYtD36r{AST7b*y@=3?A#P)s7 z0y+A!l4N;A^_-FYO{-DRp2RltKb=5LJ7oiNyrGyON1aWT#pFa|f1~^%M{>KrVv_?Gdy3L#VpO!WL!Dj>pLf>X zh)j<|(SPgBpHy^PI?2`k=Be?1!hh|LMtgIZ%6KXroGEo;C0sF=GY~1p$_;6Jcl|-> zPqsnJ9)jWqJTmlRR^PD?{Ej3<0eG>rzcZX9fQLWY5m7dL)t=` zo}0UYk#_ybq~tevXi=@8KK))GIesXr1`M`?fnQaaN@JIOu0!ckg|dd{n(Owmc#Zpq zUe|r%{Fi#u{Y-$>^Ihp$%MC*lBb4WEn1z&_nh#0kTZIfG%~p=47gCWXNoAw!zu5Yr zqP2c2L9x2zEk`5sx(iLfUr*2f8s_Cs6{6O5j`d(9N|el zD{B>GVXq;dYkr2u@yvUPBA1mpbzFNFw9Fnjuw%8e)mW~tsAgfTa&@_p%yypN+Prr! z39)%{`_{DN@u+X3Rl%`5*y=SMEj%sQkH{Alk!kPCJ%wU(om(xU`f$B_U9D|&wkJq& zcHb~~NSy^C+DdjHT7IhFl?>Q6sQ!Z$#9%x;SEw=-#u7$MmXN@{fz?Y^{Ma%=5eta{ zkmRo%|85UX#^!GWC={o970ClnP+c5@v^()~b7`?N4EX<<7$ry&>w}{os=!Y%5i99htVXRkb&cHiSRQ`O zjvxa09M1abA<+uds+*&>-AUz%X9 zeS=f_;JXbmIWpt;w{{`Ba4wwiKbfei^%U5lQoc*p+l9CeIP-mtLU-GPIN4jQjsqDs z%jo+nEX-L$C24pV#?@<2BCbyt&mp5O*L>To;;IT_xwQ?oaiG_l#iE!KJ|X1pjB4@W z0n6GYTS9sF_3NtVbazoy`YS)!p%B`h7?A;#wU=5JwvS_@v_`MAU3K4r#aDsb4un83 z;3K)P7YyQIj0535@t<_(W}u?F52U}FTuvS6Wc3GBmb;$mgPt&y%F%g;5^_-w(PKnu z+J}5`_2wS!L4k|D^E~A@JCYSux-dmg3ARX;U88 zGFefet6+{uFvz~Q)(;+8y=pe`z=N>>Z^WKpA2(IbX+3MURn#S;(Dlw5#`+>j^cTPB z#?M3sJcOubVXG4PL0zkY<68)i?48Je6EF$+ zyS>dF>+|UnGyb5}@L4miy<}&sH*&hnvser^bT`geb8aQvr>8;L5VN$Pzh*eSr2Rf> z)mLKKwW>y=TdniclzmQ)49ACr0;U%4 zQy9eLL(l(e4C6yNBZ>t1gP|XymdW6}=i+(?($I4>du{gYy?UN7YgwI$5`l@@w&Y9u zzOAj|p51-er0uox>)CT(*D+@j4)Be@$mUT0->K7V|DWnKBl~~m!|TM2+YS&QiadJ{ zQ74Fi`ZAyO*C+0%-{m7LPC~HLyT(~Y(rdh2Qz57lxd6>!UUh+hq{u9)|MK^HlW4-o zWmEOaEa^~#WW$Lxk$_$+twp-DyujJ7FIzK#XJ>8BQC9%m(BVwrd;oVOWZSlyeGFJV z48zxU{Bxal_j0>J7i$CprIMOiVWQpUeBO$J%(M;@Er27V4y&-v`FlM?SU4!r8I{gF zRjqWw#YI3BjF=ysUwz(gZ2s7D&)sg@^>)f#)_@F6sHlLv7)PSuN%D^=Us|~Qx0{sv z0nd7l1evk4C#hXLBB=$nZfWW<1N~2!1hwuT-R3w^``(^d|<{LLa zFe<=zYnz1u9FPXMsR6_;^cYxedv02h1I2&C@i*z`wp5Ux-poGKtXY8omV5c_mVuEd z!1+S}xwshF8}&@{DWI`8XaI{1`u1w89P?*905V9fSy)GNWS>kTD4+q5i+753)ugTU zzzpDp<~JV^B_|^un1S(EY`d$w-Kq-+?&<*AQ3J%fgNe98-0}iIe2UVs5v zgG})Gd=dfyVNQxJ2_f|I93uK8EZ}~D0pKTj@H|9vdt#1!zTlwfaaNs7Y(!7>5)|WK z0?+jzX*NFR^^&_dpWR>3fqfL&03;v|B{rZE9|@`7i@>-1-@PQu8#~6!;EBMHgZ>`8 zP$ZehVaI9wrzZfwEeN2OJs92}z<<-(3*@gn%k`>s65*1B!-oes!MD)dyd(%%z>;u| zl-Lvwz?!*L1@-R=Bp^5F21hzqnYah$Rwx1)AnFZbWw6Q(fpr*eEehu@4@Q^{JyJ!Df7J~|ek^)Z9xJoI z>+l?NyI^WKUVa$6fN4B)Tkr-y9sxpZ$*7WgB>vzv%p4dM=sU7~AbB3&u5&*h=?CR( z8hfle2L($R*J*fR52;qdGKm}+Uy3)WhbvH<{$*ek3~kX21uDh6;+Gob8=rK!vdURd z8A7paQFr{?=K}u7oS(#Jq@17luZkQ+6fzjkTF z;V*ueHFG?mLP1&T9N@B8tnm`RO)_NQFd7+XD0VK)umRLVKf81+|VIX!no=MiA7EAQFlIAM71UMlLpWExf2fsvj40!3+X+F8bTc61f5J z-0U!1^4 z2j`l7MC)Nf^M1mWAR+k(A$feN`=Ki_2gs?BGe_o_T|}Hd!j}N_&zHIPGx+neF~gFDR$6Jy;&^>NKt#pa(l>P2gqW3NZvuhlU_pgdljuHc2K*) zVMf>OjR(KmAfc1{6?G#=flc<{?p{JcCOtHAG1;Y@;la=8}*@tNV zf}O9LM_qx29;O1Hdhfp%$ccqNz?AyjJhqo3(Nqb6>wNth2MOa^x#we7=Fw2DQ>2X}AVHJT z(uvlw35#9SuC1!OvOboVt2H>i@+J+5&h6CpG>WnkTeLrPHG9oXUUItYg!PXA6A%aD zmz5MBqP+{cVZIG&<2i8aCmjq&pPi1`wDgMG5p;*=tCd4MFr0eDf+u_(zmeEm+ZeDz z?9dhV<8`fwS{a(X0_ioGU7{eQIiL-TMc%8w-&LE=BIX3`yHOf^sbbv|cBc{Zg9lI* zJP<*V7Lq9VPUXQrsW?XZKvkiE%57w)XAc*Uv%i@E>=OteH#~!_(or}NDV!lKf}6i$ zq%gnh@QO^d-?)J@AAc#b~hL#N2K?WKStNHN(p2S83p)BI9go10o;TXO5A?#v< zl@L2WS)aBo2LjgZ92D-}MyaomwIOhs9Sd@nSNtpuGnF=HcW{NWo@=>6%Y|EE#vBhX zZJ+y4sfstQp0wLw^Rzv#1Y5i)pUBi)F^dY#P-fR$4i7gqY0T;%i%bf&n%1uPA7nf! zZ%4;z=HcMBn=~`qKJumg6QI#m#ZrR9NgOOrSYUihJK8HI-m0BeEDo5xg?=^0d%Q*I5zn1#@= z*l?x|v#o^u3xsq7nHV_SWAwUvs@S*NkZg=+&gWE=Z%vvYdk1fv06cV10a#{!Mo0RS zZ1@n_U7c1T9R7b+f4UUb3Koyp)KqoOjJT>lybgyyydzk)nfJ)iLZ^$6iQC{*&yUvP zQnYD*CKdXLgTX8;F7;(Z=w!~>f1o94LqUP(+QR-X#YUR>`;8bz#BYZTN7w*SqUbWk za^Zury^jw8wMAirJg(O;V<(XTFA%9|6*W4Wno{mnTWp&8H-)&_ne$4Fg>xDSJ|Z+# z6|iMm4ke8?a|MytThrs<#WNwJA}Lf4$1GVc^`;{ZIgzMIQ=XO0$H<_vBomCJe?=x+ zCXz*rdL`#{=NzZEi5$4mW=oZ;`?bseg2|FRQ3=f7EN@>R`S|R+DR)7`@!LLWJ>TOA z&R6QR{E&?ubZf~OBd95kckR!1aH5*3Ml?D-_ z4nd`65yJ5@#&k+Y<^{7eS}2~ZeDytu!mQ4)L$W!Bi#jL@{JJ9ey^Ky zMZ)PS%39lM2RE!m+tZ1(18SpYll);e^%E^hbSYECc}5*klZ2tQV%7EfVAiJcNlo<> zvpdtGA|yeH5hs(YB+DpXEh6fF#GNhr9m+XnOTQ08A+UHlR3$1aBBx0IT9-*vK3dF@ zYvwR(kxj+ZIH5T^wBn`>!EXS=`F(R&~*ycA;CaHEpn6!!E@iS&AOi|FK4{<8I1AwkX)=!`&pHQcerS?jAGXi8 zSJ`Gd5@x2EN;>Don|RxiqEa!tcSx{R;7LIZo{e{Vq{{dVZ|)b;%K zDJ0H)hfz;T_0bn-X`R}#_g>to86zqjV9Z-_Q35uHFs^>jOK@DL#Qrv2RH!6>!s|F) zJ8}2b*$)ZQ+&j7wp!vW|Ub;z$T9j^@g{J2JGYo1Is(%4Tm7;MFfU7{Nomu z`2Fyt;vA?WWwoGV^0oVMq1_?9ZFs@`uhr*bWK_7jy{D{Pu1Zm2E=NiliG-{pa|#_I z{RsrfYn7Be=J{Z$qj5(pk_7Mg*Z!@HIQg&xVhJ(n-hy+<(v~6{Q&)B2GzncihRfR{ zYCCvVwd{P^xf>Ik5QBp~~2pC7mz+uT*6WEiH{(|@H^@K0%q-KLob_wbi$QG|E&Ne`HD@*2gI z3PHN68(2T?;OXxE&=6~35h<*h3LC&aYzK=Zh?`fGcxV;AgKDeXHkaWE@JizKQ4*Qq zU}jp3>Ev`j&&X8!EX?lUneL58F;P@xnnuC%V@ISJ00s3PWQ`vOT_!+a7mAbb|JGJ; zdn;gpDh0q{F{i5xoi=NG)X~eB#!+^bXQN}L922Kxe7Dv<4{Dp;=W5c3fg;C>*%JvM z;tjL#_>U`OuO2gHjJJ}4fdbvUf!d;nM+mh_1ciwazA>#mL$D(0e9^q`Emf$^rdSi* z0@{c1d{Vi+U}j9KY3VXRec7I@#(ppjz?rQ&ygW1~pr93P?hq~hY-laR0aPW`iU*y? zGMT_eWdA~R4#xXH71C!!DJC(~Fa;Q?nC2zR{xUK#25ClFhH&+0##PD5DTF&#z@&%% zzUcb=<>*pOM9M=$%;)JaJ+o3R7&EP^ed|QWU$aur5%!9Fy=$lg{s2t>+GrTvS58BABvs zpWUq`(xkaHFXlL3LrWWiaex_RH|`m?^7%d0e04X``O<2mrILGrPd-cs@vpr6AFy^c zwLD7!+sQ~q205%}kgi>-xn=eO_CqkC*L(*YTm(8Bb7u#I*Sr@T94;;#-1X&{ZI)r` zonvU4<)m$f;SaFNpqPD2*NDpj(>8!xA0P~Gkjb+(q@5oi>LwuF*{GX=q~!<``r$L8 zL))@`n2z`Rl#L>yAwlj}&Wz@zdP9>+)o+x)7iXPsfyoS6$);T4h1NQvvR8Ydq0eNb zT6PP|bcu(?>8Ke44e?7Luu9p)W0b1MV^}TXB=D`NKOQ>6Aza;SK|WiT2O5Ry!AsuR zYi$#G4kyzo5{XJjr5d*#(w22Dq4P$gNw7!CA{mnAiX<1X$pTFpo)|Mjg?0rrQ?MNP zLkuQIN5d7D-brO~VWKd~4?YS}5|k9C2_QgltNL`P7C*2*GgP>U8yBdNz`@{A8gwE` zXZp~|omhFM4sDttO3MRXirnTGl*8&)wY(BVSxt#!1V8WGE>Y|I-YYxi;K==LLCW9= zoZHYn*C5fNxR63g-^n18NfD`;7^j?P*CAfYxw_nZJGV)+Vp>b*V1r`S($vew)oJ!3 zUF+tT;_&0fSut-CC3=}74G}8M)R@Js@^#~yBsJOmQTspMpzJu~(jmhR&BMv5DV5_R z)w!m1nq)&Sfj(golN#A;WRsKnhAjV`vQg?ObkJ5*llLGtu_4ag@&4$%$&r;-xAv)N}z$lb<}1C zn6r&J2}ebv)T#z_zhBzY(Y6+$K3PBxKuW4jQhPPJ?p32hcpWRv~l~%>0h={|uDKhCtM@Z8#pmIxuY9^}`H` z*a{PK-+8v-h8hdsBTnaWGfaGqkDOREzo(P}P`xKy3rhG1Wedt~t_OOKj74UGQ4p2u zqTJb@9G&q0{^J>T-$3S52#?M6oiL_ELTX1?+2*Rem_(SF#zLFnsAu$PmnohoH^9~r z-N*X%Wz)Ksr!%;?u7`*Cet#!T;($@&s4eT{MZGdUNy6#78%mP+>yq?o5|_X=xFwDb zk8H6cJL7$GKdjBE ztAp>s#73r)lEM2aUdh^9^1ZV{r{wy<&}7^+EJ{SpB*?UbFdk0 zaYg2ZtRE$t{`xY;$sdaLSz2<$65e_YdN1J4udJDKC$nPZab1N#KQY$ z30H^Q`zMQ{$ky6gJbW8B+s-gv6@~Pt_^qZIy}=R+lQ9vd~(#iqb-R`I&B1 z=$zsLmfUf}&=4)cKIf9zb%Q!qVf`@hJhamF{m{@9Bl`UV(KO}Xd=*L;HI9bA`41Zt zOOXEWU;^sB*9A}(gLWwFnJ9+A2eWSd34?KI*iPs(R+0~1cR5Flp{q{jy9Rq4Zmp1r zok(dzRe=P@1w5$HHaymCfdlY}gn|I#}{%En{h!-j!?bq_W=}*q@(;@Pt>le))J95CKA*0&K$K ziRpQO%vS6Zr&0M!8vx>lHT9grztMyesU|}-?FvP7Jzq&@>2Od#QQ)UlZzPes;bm(5 z&^WSR$B8o%dPxO0T)q)}S3gG;WBk=tAC|w+7FJO=Ojb~pEk z-?UU^URK_@(DGrevPe`WexdB5Tm9S0xM5R7L<_`a9R}u7Hf&$MWP6Sz#mR4GM>g1A zXMr!DV5ir`NmLQX_s~XQvv*9(4;RHdMI8i4R@6@P>+fOUx&Ho>M68kT^M~%PcTkv!8_S;2%_yv_WPYNE4tUV! zIQ@v1TKCDVY98jVDh=HOtpde^)BD6GEH4YwqreL;ZXUavvBM#cV%wPaymnMC8`iK% z#fOux_>Qwf=y81UhKZxQU9{QTbZ6(58Cd6M=gscx>ynb_G||G4G6ylnaM=K! z%32VTe(2f+Y$Buw4r~%1cVO6B;JY!nSjh2Rq%REcKA1QG>!>d;!JR^q6;3wimm7oX z1Eqe^Et0K$N%qS)wgD0YE=N$rw_nA7e4u(i3qUw5piT*%aE0Wci$(Db+kRuX82!~A zPbryDA_)EdywiA~Ukl9^*+%8&=?vlt9d6UJ&FrcS-$^I6Z**q%)UP%hbG2QJC2n>s*&$eq96h?Rs$SB8H52Tnb-z z9iNVoG)P!Tnuv(|Hu+;a56%+n-f$$jg(grQ!z1xa+1WS68ypNC-GA$(E(kmj6_HB3 z@A!Q%P4e}GlZFu`EgM~ID#dw5(j|wAhRR)MxBUyvX;$f?4~j^?#pXH3cgIC)_FQY~ z1+Q@(co1|IuatY!*YvDI>0}qAWL>wsR2OF?2!@{^3ip=?m)n$`*APv#5w-aB%@9SK z;@qclT#>wtMd%rtZGNF*!$4<=ly(cdR=jE5Kgy`kJ8i8v60zo+C(ydW`n#g$c@`h6 zbU`IBk%fPAOcB$n@9CpISJA+C!ZlyNPD?j2!F;%eXTx*3ZQB3==mW7wtQk)6utF6T zQnED)dl`f6z~kWxf={qGVeWW8|5<3V2yL5fKy;Aa*j4{zFrk-HYB_j^Sm z5bTTog`Quu;r<6EY~@z?dwctcnCSt^&oO;!C`OUPFm{Rnah6Djh|tIm|KoK8g4n-% z-w@$YC$UbhW3*&7?Xfh2hdHo(N!uH(>t8juceW7B70!L*4z9fbNF@m3(8!%)SYJ%$ z2lTfudo+jJM94mC#yH~N{yQK0EF>OHoIO>tbMIfWO>%W7%QedjJ%N$T*qTZ!g|QXT zQLhP2F!&Udj*v{kx>-w0)pJ-1GcA%uiX}fJE?2Pf35QV^oB7q%_&eZo^+ZxhSqX-6 z*0F~&7_?j&sp7v8U2XNSMpL8sDL&0kt8oC&_Nel?^AyfcBQUa#qM6Q$ft5n0n&#uP zbm=FDCm$XW8mB+pjm4yVVK(SWW&PB5PDWMQ)yY!zJd$N9=|*vtOR5Tt5CqORJre0) z3f!a?NEW=`df(C8!Z0g6J|TnO*s6HN8vl(#$j0#hDaA5zaQp{rSSMjJI*=YEL5za?izi6t#0eR|!=>uMJnWwCp%>#(l`b3L7! z@421H8P~3u)Hh$MCJokOxn(Kg-8RhBP(b1G{C#mw{`7vdKJtDig7$MUolDQU<5pM- z%{w((x`xi%f%=RT=4_q$bB=$_vF|R^&Dm7oc1ikrlAqhYUS%=v$F*M*E%M2E>yz^* zEShwq(MW8$%wmlBO_2JR;Gax06OCjJ;?2*BFeKv=r}udbH|-&A&$V7 z2^0Y>U+TMVL9HmT#SGvO$OjkB+an`jEm& z{YxwBBDZ?@xZtjb0SzQW_1<@u;O2{pG*O@{o?|Vn2l369<;&CLx%1T<4n`OW-fejZ zU7@WuGI-qMFCb>ji%n!`)|0Bx0MxOfp=mLk$HPHY(N$jhpRB7oZTY>YGOZy#$k$1! z^$Fd=iP=9_xxDtS&gbN39W2*+Hof$$f>0#;b6iAdP(EY6)!cM81y1^04ygv9 zKaLvHl<$Y`n$~K1JF+``?9yPwE4Bzx;~otJDVlgJkFTX1zt4W7Kr*AH*-3d_SSZI{ z7_Yx4c2%6s8@m3Yg8-E}#?N>e6~tJhMKghAIUnxPd+IHUy3}BJ!@fBxu;k8?19-r? z%^w-=+mN59L@03Jqu+;O(<1ViN7A$3?4M2lxa1@qJy{yVLTbB^`wciaa!?$M$R%+pgzt?T=RU-z^3($v3_t#|i7xBZ$1 z){}ISmA^#S)14BvsUk1E7|z=0eXqUxn~%_odcw{6M5prnl^@=nC)VvOdRWiyF{L_B zof}S@DlXQ@k ztrQwQ8f8&99nyRr=vK2OZz3qMtv&rMPE|>eWpuRQ_2Q%XrZ^93|4{C~B%N1G;Bv{T zvAbCktK9DxRL+ygo_ zbfAzSbxKl1cH?rVao3y4mzOv~$K@JoXpzjtu4P)%8i5H%Ze(%F)~|=XV=Fv*uOI?U z|8j~?rEUaae9U=v0sSGLtC}~Nj%yYFv9;0z;(f@ZBjw`g!df-kar+Ou9^YU%G&Fmg z#eQN^z%&XjTwJN_9|UyNKP4f5wh85^vti*SiMC`=sFqagaD8(#^-=q3dB_6xg@j}O z8Ql(=1+pSf2$k=Eblc3u?)r*SFu)x-!XnXxw*12yGCw_s z6sh$ZgUCVQS3H6@{E+12c9{pazIU`6f3=x(aC~vSk*PTuF5_=rQP*!!+_H= zM*C36H72vh{TPE|(W&Vue;^gXBfwcuAe>6@7N`YI9jCZMB{%+Pz`;YLD3!P^P^zuH z7}nyQyr+W&z1781z)SbuBq4mGCI>vzl*N2#QBy_$7=|I6ftB!(Vg5_$&E^`5;1 z&4g=S!W?B!Zqer_3X`Ut=8|R|w5))66b#jsU0wB|%feKr3kVg}L8 z|Ja9Rj=f+1Go5t&jP2M9bL109f-|d970iK)j)L;@OB75kfo+Z;E`8ud+W88g_6Lyd zmYGwMTBM-wmXlbL>XMqApOVU@52>Ldf>P7q)sc~rDVKh@LNrjH5fH|LOi4+t016lY zEdcWE?6`_cic%AExhm%9p0V|IN|ZSE@wZjhtoLcNrj=cpoWFoWX~&K$3Z^?uo+Rnk zF}`$u@hH4t@-#N}gG*g!y;AnrX>P@}@cA>V)AQx8pZ(l%;$gyxy&Y^)&W|tcPz;o_ znI+sSe$3chevk7jkw)34?itRk0@8twD!W5CUaE?^eVgBPU`}9QM6_00)(k7>T(6@S zx2!1MGB=xPZn#$GZJE->-SS$k@2saDJ1k$?c~8Hz^*Fy)^S;mVV$GtZYYj~;edB@; zoSql%UEEw4%Od>TH8A+lpWFBDMcp|yi|d;Iw{JH$eBLTx$#lj`TNq2NUtE${R8mm{ R3@}qe3*h28RaIAiHvpU*$F%?e literal 0 HcmV?d00001 diff --git a/lessons/01-introduction/clippy.jpg b/lessons/01-introduction/clippy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cf490ba9e1f9daaabae3f8edf2b01b1f7a7d97e1 GIT binary patch literal 27148 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 literal 0 HcmV?d00001 diff --git a/lessons/01-introduction/conditionals.rs b/lessons/01-introduction/conditionals.rs new file mode 100644 index 0000000..441aba6 --- /dev/null +++ b/lessons/01-introduction/conditionals.rs @@ -0,0 +1,20 @@ +#![allow(unused_variables)] + +fn main() { + let x = 42; + + if x == 42 { + println!("x is 42"); + } else if x == 43 { + println!("x is 43"); + } else { + println!("x is not 42 or 43"); + } + + // we can also use ifs as expressions + let a_or_b = if x == 0 { + "a" // notice no semicolon at the end + } else { + "b" + }; +} diff --git a/lessons/01-introduction/cpp_meme.jpg b/lessons/01-introduction/cpp_meme.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4ec2e1731afa9fb9042bfe8260e629dde748ab6e GIT binary patch literal 128164 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 z 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 + +#define LENGTH 3 + +int main() { + //# Syntax error + // printf("hello world"; + + //char* array[LENGTH] = {"hello", "ancient", "world!"}; + + //# Array out-of-bounds with a statically known index + // printf("%s\n", array[LENGTH]); + + //# Array out-of-bounds with a dynamically computed index + // for (int i = 0; i <= LENGTH; i++) { + // printf("%s\n", array[i]); + // } + + //# Doing God knows what + // char* format = "a very innocent hello %s"; + // printf(format); + + //# Division by zero + // int joy_division = 1/0; + + // int joy = 0; + // int joy_division = 1/joy; + + // int joy = 0 ? 1 : 0; + // int joy_division = 1/joy; + + // printf("joy division equals %d", joy_division); + + return 0; +} diff --git a/lessons/01-introduction/errors_demo.cpp b/lessons/01-introduction/errors_demo.cpp new file mode 100644 index 0000000..1c7d88b --- /dev/null +++ b/lessons/01-introduction/errors_demo.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +using std::cout; +using std::endl; + +int main() { + //# Syntax error + // cout < "hello world"; + + // constexpr int length = 3; + // std::array array = {"hello", "old", "world!"}; + + //# Array access with an out of bounds index and bounds checking during compile time + // cout << std::get(array) << endl; + + //# Array access with an out of bounds index and bounds checking during runtime + // cout << array.at(length) << endl; + + //# Most common access without any checks + // cout << array[length] << endl; + + //# Array out-of-bounds with a dynamically computed index + // for (int i = 0; i <= length; i++) { + // cout << array.at(i) << endl; + // } + + //# This will be there in Clang 14 ... + // std::string format = std::format("a very innocent hello {}"); + // cout << format << endl; + + //# ... but for now, this is doing God knows what + // const char* format = "a very innocent hello %s"; + // printf(format); + + //# Division by zero + // int joy_division = 1/0; + + // int joy = 0; + // int joy_division = 1/joy; + + // int joy = false ? 1 : 0; + // int joy_division = 1/joy; + + // cout << "joy division equals " << joy_division << endl; + + return 0; +} diff --git a/lessons/01-introduction/errors_demo.rs b/lessons/01-introduction/errors_demo.rs new file mode 100644 index 0000000..bf5a394 --- /dev/null +++ b/lessons/01-introduction/errors_demo.rs @@ -0,0 +1,29 @@ +fn main() { + //# Syntax error + // println("hello world"); + + // let array = ["hello", "new", "world!"]; + + //# Array out-of-bounds with a statically known index + // println!("{}", array[3]); + + //# Array out-of-bounds with a dynamically computed index + // for i in 0..=array.len() { + // println!("{}", array[i]); + // } + + //# An unsuccessful attempt at emulating C++'s ability to read the memory we're not supposed to access + // let format = "a very innocent hello {}"; + // println!(format); + + //# Division by zero + // let joy_division = 0/0; + + // let joy = 0; + // let joy_division = 0/joy; + + // let joy = if false {1} else {0}; + // let joy_division = 0/joy; + + // println!("{}", joy_division); +} diff --git a/lessons/01-introduction/functions.rs b/lessons/01-introduction/functions.rs new file mode 100644 index 0000000..2987a36 --- /dev/null +++ b/lessons/01-introduction/functions.rs @@ -0,0 +1,12 @@ +fn get_5() -> u32 { + 5 // we could also write "return 5;" +} + +fn print_sum(a: u32, b: u32) { + println!("a + b = {}", a + b); +} + +fn main() { + let a = 100; + print_sum(a, get_5()); +} diff --git a/lessons/01-introduction/hello_world.rs b/lessons/01-introduction/hello_world.rs new file mode 100644 index 0000000..fa9fb84 --- /dev/null +++ b/lessons/01-introduction/hello_world.rs @@ -0,0 +1,4 @@ +fn main() { + let name = "World"; + println!("Hello, {}!", name); // using the println! macro +} diff --git a/lessons/01-introduction/index.html b/lessons/01-introduction/index.html new file mode 100644 index 0000000..3888984 --- /dev/null +++ b/lessons/01-introduction/index.html @@ -0,0 +1,672 @@ + + + + + + + + Rust course + + + + + + + + + + + + + +

      + +
      + + +
      + +
      + +
      +
      +
        +
        +
        + +
        + +

        Introduction to Rust

        +

        + 2024-10-03 (last edit: 2024-09-20) +

        +

        Logo

        +

        A language empowering everyone to build reliable and efficient software.

        +

        (unofficial logo)

        +

        Why use Rust?

        +
          +
        • It is safe (compared to C++ for example, as we will see in a minute)
        • +
        • It is fast (because it is compiled to machine code)
        • +
        • It is ergonomic and pleasant to use (static typing, expressive type system, helpful compiler +warnings)
        • +
        • It +is loved by programmers
        • +
        • It provides excellent tooling
        • +
        +

        Why learn Rust?

        +

        Even if you don't end up using Rust, learning it expands your horizons

        +
          +
        • it helps especially with the awareness of what you can and can't do in concurrent applications
        • +
        • it helps you understand memory management and learn its good practices
        • +
        +

        Why not to learn Rust?

        +
          +
        • Some people say Rust is too hard to learn because of the borrow checker
        • +
        • Once you get to know Cargo you won't ever want to use a language without a built-in package +manager ;)
        • +
        • You will start hating C++
        • +
        +

        Demos

        +

        Meme

        +

        Let's compare the same code written in C, C++ +and Rust.

        +

        Code you sent in previous editions!

        +

        Aleksander Tudruj

        +
        #include <iostream>
        +#include <unordered_map>
        +
        +using name = std::string;
        +using age = int;
        +using person = std::pair<name, age>;
        +using address = std::string;
        +using address_book = std::unordered_map<person, address>;
        +
        +void print_address_book(const address_book &book)
        +{
        +    for (const auto &[person, address] : book)
        +    {
        +        std::cout << person.first << " is " << person.second << " years old and lives at " << address << std::endl;
        +    }
        +}
        +
        +int main()
        +{
        +
        +    address_book people{};
        +    people.insert({{"John", 20}, "221B Baker Street, London"});
        +    people.insert({{"Mary", 30}, "Avenue des Champs-Élysées, Paris"});
        +    people.insert({{"Jack", 73}, "Wall Street, New York"});
        +    print_address_book(people);
        +
        +    return 0;
        +}
        +
        +
        +

        (Download the source code for this example: tudruj.cpp)

        +

        Krystyna Gasińska

        +
        # sample 1 - different ways of removing elements from the list while iterating
        +list1 = [1, 2, 3, 4]
        +for idx, item in enumerate(list1):
        +    del item
        +list1
        +
        +# [1, 2, 3, 4]
        +
        +list2 = [1, 2, 3, 4]
        +for idx, item in enumerate(list2):
        +    list2.remove(item)
        +list2
        +
        +# [2, 4]
        +
        +list3 = [1, 2, 3, 4]
        +for idx, item in enumerate(list3[:]):
        +    list3.remove(item)
        +list3
        +
        +# []
        +
        +list4 = [1, 2, 3, 4]
        +for idx, item in enumerate(list4):
        +    list4.pop(idx)
        +list4
        +
        +# [2, 4]
        +
        +# sample 2 - string interning
        +a = "abc"
        +b = "abc"
        +a is b
        +
        +# True
        +
        +a = ''.join(['a', 'b', 'c'])
        +b = ''.join(['a', 'b', 'c'])
        +a is b
        +
        +# False
        +
        +a = "abc!"
        +b = "abc!"
        +a is b
        +
        +# False
        +
        +# sample 3 - chained operations
        +(False == False) in [False]
        +
        +# False
        +
        +False == (False in [False])
        +
        +# False
        +
        +False == False in [False] # unexpected...
        +
        +# True
        +
        +# sample 4 - is operator
        +a = 256
        +b = 256
        +a is b
        +
        +# True
        +
        +a = 257
        +b = 257
        +a is b
        +
        +# False
        +
        +a, b = 257, 257
        +a is b
        +
        +# True
        +
        +257 is 257
        +
        +# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
        +# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
        +# C:\Users\kgasinsk\AppData\Local\Temp\ipykernel_15776\331119389.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
        +#  257 is 257
        +
        +# sample 5 - local variables
        +def f(trufel):
        +    if trufel:
        +        y = 1
        +    y += 1
        +
        +f(True) # everything is fine
        +
        +f(False) # gives error: local variable 'y' referenced before assignment
        +
        +# ---------------------------------------------------------------------------
        +# UnboundLocalError                         Traceback (most recent call last)
        +# Input In [17], in <cell line: 1>()
        +# ----> 1 f(False)
        +
        +# Input In [15], in f(trufel)
        +#       3 if trufel:
        +#       4     y = 1
        +# ----> 5 y += 1
        +
        +# UnboundLocalError: local variable 'y' referenced before assignment
        +
        +

        (Download the source code for this example: gasinska.py)

        +

        Antoni Koszowski

        +
        // mutowalność jest wbudowana w język
        +
        +type S struct {
        +    A string
        +    B []string
        +}
        + 
        +func main() {
        +    x := S{"x-A", []string{"x-B"}}
        +    y := x // copy the struct
        +    y.A = "y-A"
        +    y.B[0] = "y-B"
        + 
        +    fmt.Println(x, y)
        +    // Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified!
        +}
        +
        +// slices i kwestia append
        +
        +func doStuff(value []string) {
        +    fmt.Printf("value=%v\n", value)
        + 
        +    value2 := value[:]
        +    value2 = append(value2, "b")
        +    fmt.Printf("value=%v, value2=%v\n", value, value2)
        + 
        +    value2[0] = "z"
        +    fmt.Printf("value=%v, value2=%v\n", value, value2)
        +}
        + 
        +func main() {
        +    slice1 := []string{"a"} // length 1, capacity 1
        + 
        +    doStuff(slice1)
        +    // Output:
        +    // value=[a] -- ok
        +    // value=[a], value2=[a b] -- ok: value unchanged, value2 updated
        +    // value=[a], value2=[z b] -- ok: value unchanged, value2 updated
        + 
        +    slice10 := make([]string, 1, 10) // length 1, capacity 10
        +    slice10[0] = "a"
        + 
        +    doStuff(slice10)
        +    // Output:
        +    // value=[a] -- ok
        +    // value=[a], value2=[a b] -- ok: value unchanged, value2 updated
        +    // value=[z], value2=[z b] -- WTF?!? value changed???
        +}
        +
        +// error handling
        +
        +len, err := reader.Read(bytes)
        +if err != nil {
        +    if err == io.EOF {
        +        // All good, end of file
        +    } else {
        +        return err
        +    }
        +}
        +
        +
        +// interfejs nil
        +
        +type Explodes interface {
        +    Bang()
        +    Boom()
        +}
        + 
        +// Type Bomb implements Explodes
        +type Bomb struct {}
        +func (*Bomb) Bang() {}
        +func (Bomb) Boom() {}
        + 
        +func main() {
        +    var bomb *Bomb = nil
        +    var explodes Explodes = bomb
        +    println(bomb, explodes) // '0x0 (0x10a7060,0x0)'
        +    if explodes != nil {
        +        println("Not nil!") // 'Not nil!' What are we doing here?!?!
        +        explodes.Bang()     // works fine
        +        explodes.Boom()     // panic: value method main.Bomb.Boom called using nil *Bomb pointer
        +    } else {
        +        println("nil!")     // why don't we end up here?
        +    }
        +}
        +
        +// ubogie struktury danych, takie customowe tracą type safety m.in poprzez castowanie do interface{}
        +// kiedyś brak generyków, choć teraz w znacznym stopniu problem został rozwiązany.
        +
        +

        (Download the source code for this example: koszowski.go)

        +

        Mieszko Grodzicki

        +
        def add_contents(input_list, contents=[]):
        +     for val in input_list:
        +         contents.append(val)
        +     return contents
        +
        +print(add_contents([1])) # [1]
        +print(add_contents([2])) # [1, 2]
        +
        +

        (Download the source code for this example: grodzicki.py)

        +

        Installing Rust

        + +

        Useful tools

        +

        Clippy

        +
          +
        • cargo clippy (for static analysis)
        • +
        • there's also cargo check, but it's less powerful than clippy
        • +
        • cargo fmt (for code formatting)
        • +
        +

        Rust Playground

        + +

        Hello world

        +
        fn main() {
        +    let name = "World";
        +    println!("Hello, {}!", name); // using the println! macro
        +}
        +
        +
        +

        (Download the source code for this example: hello_world.rs)

        +

        Variables

        +
        #![allow(unused_variables)]
        +#![allow(unused_assignments)]
        +
        +fn main() {
        +    let x = 40; // inferred type
        +    let y: i32 = 100; // specified type
        +
        +    {
        +        let x = 40 + 2; // shadowing
        +        println!("x is {}", x); // prints 42
        +    }
        +
        +    // x = 0; // compilation error, variables are by default immutable
        +    let mut x = 40; // declare as mutable
        +    x = 0; // now we can reassign
        +
        +    x += 1; // x = x + 1
        +}
        +
        +
        +

        (Download the source code for this example: variables.rs)

        +

        Conditionals

        +
        #![allow(unused_variables)]
        +
        +fn main() {
        +    let x = 42;
        +
        +    if x == 42 {
        +        println!("x is 42");
        +    } else if x == 43 {
        +        println!("x is 43");
        +    } else {
        +        println!("x is not 42 or 43");
        +    }
        +
        +    // we can also use ifs as expressions
        +    let a_or_b = if x == 0 {
        +        "a" // notice no semicolon at the end
        +    } else {
        +        "b"
        +    };
        +}
        +
        +
        +

        (Download the source code for this example: conditionals.rs)

        +

        Loops

        +
        #![allow(unused_variables)]
        +
        +fn main() {
        +    for i in 0..10 {
        +        println!("i is {}", i); // i in [0, 10)
        +    }
        +
        +    let mut x = 0;
        +
        +    while x < 50 {
        +        x += 1;
        +    }
        +
        +    let mut y = 0;
        +    let mut iterations = 0;
        +    loop {
        +        iterations += 1;
        +        if iterations % 2 == 0 {
        +            continue;
        +        }
        +        y += 1;
        +        if y == 10 {
        +            break;
        +        }
        +    }
        +
        +    // we can use labels to refer to a specific loop
        +    let mut count = 0;
        +    'counting_up: loop {
        +        let mut remaining = 10;
        +
        +        loop {
        +            if remaining == 9 {
        +                break;
        +            }
        +            if count == 2 {
        +                break 'counting_up; // ends the outer loop
        +            }
        +            remaining -= 1;
        +        }
        +
        +        count += 1;
        +    }
        +
        +    // We can use break with a value.
        +    // Because loops are expressions too,
        +    // the value we break with will be returned from the functions
        +    let mut counter = 0;
        +    let value = loop {
        +        counter += 1;
        +        if counter == 10 {
        +            break 32;
        +        }
        +    };
        +}
        +
        +
        +

        (Download the source code for this example: loops.rs)

        +

        Functions

        +
        fn get_5() -> u32 {
        +    5 // we could also write "return 5;"
        +}
        +
        +fn print_sum(a: u32, b: u32) {
        +    println!("a + b = {}", a + b);
        +}
        +
        +fn main() {
        +    let a = 100;
        +    print_sum(a, get_5());
        +}
        +
        +
        +

        (Download the source code for this example: functions.rs)

        +

        Test assignment (not graded)

        +

        Click here

        +

        Obligatory reading

        + +

        Additional reading

        + + + +
        +
        + + + + +
        + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/01-introduction/loops.rs b/lessons/01-introduction/loops.rs new file mode 100644 index 0000000..8a02d72 --- /dev/null +++ b/lessons/01-introduction/loops.rs @@ -0,0 +1,55 @@ +#![allow(unused_variables)] + +fn main() { + for i in 0..10 { + println!("i is {}", i); // i in [0, 10) + } + + let mut x = 0; + + while x < 50 { + x += 1; + } + + let mut y = 0; + let mut iterations = 0; + loop { + iterations += 1; + if iterations % 2 == 0 { + continue; + } + y += 1; + if y == 10 { + break; + } + } + + // we can use labels to refer to a specific loop + let mut count = 0; + 'counting_up: loop { + let mut remaining = 10; + + loop { + if remaining == 9 { + break; + } + if count == 2 { + break 'counting_up; // ends the outer loop + } + remaining -= 1; + } + + count += 1; + } + + // We can use break with a value. + // Because loops are expressions too, + // the value we break with will be returned from the functions + let mut counter = 0; + let value = loop { + counter += 1; + if counter == 10 { + break 32; + } + }; +} diff --git a/lessons/01-introduction/students/gasinska.py b/lessons/01-introduction/students/gasinska.py new file mode 100644 index 0000000..e4989f1 --- /dev/null +++ b/lessons/01-introduction/students/gasinska.py @@ -0,0 +1,107 @@ +# sample 1 - different ways of removing elements from the list while iterating +list1 = [1, 2, 3, 4] +for idx, item in enumerate(list1): + del item +list1 + +# [1, 2, 3, 4] + +list2 = [1, 2, 3, 4] +for idx, item in enumerate(list2): + list2.remove(item) +list2 + +# [2, 4] + +list3 = [1, 2, 3, 4] +for idx, item in enumerate(list3[:]): + list3.remove(item) +list3 + +# [] + +list4 = [1, 2, 3, 4] +for idx, item in enumerate(list4): + list4.pop(idx) +list4 + +# [2, 4] + +# sample 2 - string interning +a = "abc" +b = "abc" +a is b + +# True + +a = ''.join(['a', 'b', 'c']) +b = ''.join(['a', 'b', 'c']) +a is b + +# False + +a = "abc!" +b = "abc!" +a is b + +# False + +# sample 3 - chained operations +(False == False) in [False] + +# False + +False == (False in [False]) + +# False + +False == False in [False] # unexpected... + +# True + +# sample 4 - is operator +a = 256 +b = 256 +a is b + +# True + +a = 257 +b = 257 +a is b + +# False + +a, b = 257, 257 +a is b + +# True + +257 is 257 + +# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? +# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? +# C:\Users\kgasinsk\AppData\Local\Temp\ipykernel_15776\331119389.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="? +# 257 is 257 + +# sample 5 - local variables +def f(trufel): + if trufel: + y = 1 + y += 1 + +f(True) # everything is fine + +f(False) # gives error: local variable 'y' referenced before assignment + +# --------------------------------------------------------------------------- +# UnboundLocalError Traceback (most recent call last) +# Input In [17], in () +# ----> 1 f(False) + +# Input In [15], in f(trufel) +# 3 if trufel: +# 4 y = 1 +# ----> 5 y += 1 + +# UnboundLocalError: local variable 'y' referenced before assignment \ No newline at end of file diff --git a/lessons/01-introduction/students/grodzicki.py b/lessons/01-introduction/students/grodzicki.py new file mode 100644 index 0000000..1454659 --- /dev/null +++ b/lessons/01-introduction/students/grodzicki.py @@ -0,0 +1,7 @@ +def add_contents(input_list, contents=[]): + for val in input_list: + contents.append(val) + return contents + +print(add_contents([1])) # [1] +print(add_contents([2])) # [1, 2] \ No newline at end of file diff --git a/lessons/01-introduction/students/koszowski.go b/lessons/01-introduction/students/koszowski.go new file mode 100644 index 0000000..2916f91 --- /dev/null +++ b/lessons/01-introduction/students/koszowski.go @@ -0,0 +1,88 @@ +// mutowalność jest wbudowana w język + +type S struct { + A string + B []string +} + +func main() { + x := S{"x-A", []string{"x-B"}} + y := x // copy the struct + y.A = "y-A" + y.B[0] = "y-B" + + fmt.Println(x, y) + // Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified! +} + +// slices i kwestia append + +func doStuff(value []string) { + fmt.Printf("value=%v\n", value) + + value2 := value[:] + value2 = append(value2, "b") + fmt.Printf("value=%v, value2=%v\n", value, value2) + + value2[0] = "z" + fmt.Printf("value=%v, value2=%v\n", value, value2) +} + +func main() { + slice1 := []string{"a"} // length 1, capacity 1 + + doStuff(slice1) + // Output: + // value=[a] -- ok + // value=[a], value2=[a b] -- ok: value unchanged, value2 updated + // value=[a], value2=[z b] -- ok: value unchanged, value2 updated + + slice10 := make([]string, 1, 10) // length 1, capacity 10 + slice10[0] = "a" + + doStuff(slice10) + // Output: + // value=[a] -- ok + // value=[a], value2=[a b] -- ok: value unchanged, value2 updated + // value=[z], value2=[z b] -- WTF?!? value changed??? +} + +// error handling + +len, err := reader.Read(bytes) +if err != nil { + if err == io.EOF { + // All good, end of file + } else { + return err + } +} + + +// interfejs nil + +type Explodes interface { + Bang() + Boom() +} + +// Type Bomb implements Explodes +type Bomb struct {} +func (*Bomb) Bang() {} +func (Bomb) Boom() {} + +func main() { + var bomb *Bomb = nil + var explodes Explodes = bomb + println(bomb, explodes) // '0x0 (0x10a7060,0x0)' + if explodes != nil { + println("Not nil!") // 'Not nil!' What are we doing here?!?! + explodes.Bang() // works fine + explodes.Boom() // panic: value method main.Bomb.Boom called using nil *Bomb pointer + } else { + println("nil!") // why don't we end up here? + } +} + +// ubogie struktury danych, takie customowe tracą type safety m.in poprzez castowanie do interface{} +// kiedyś brak generyków, choć teraz w znacznym stopniu problem został rozwiązany. \ No newline at end of file diff --git a/lessons/01-introduction/students/tudruj.cpp b/lessons/01-introduction/students/tudruj.cpp new file mode 100644 index 0000000..a5e48fd --- /dev/null +++ b/lessons/01-introduction/students/tudruj.cpp @@ -0,0 +1,28 @@ +#include +#include + +using name = std::string; +using age = int; +using person = std::pair; +using address = std::string; +using address_book = std::unordered_map; + +void print_address_book(const address_book &book) +{ + for (const auto &[person, address] : book) + { + std::cout << person.first << " is " << person.second << " years old and lives at " << address << std::endl; + } +} + +int main() +{ + + address_book people{}; + people.insert({{"John", 20}, "221B Baker Street, London"}); + people.insert({{"Mary", 30}, "Avenue des Champs-Élysées, Paris"}); + people.insert({{"Jack", 73}, "Wall Street, New York"}); + print_address_book(people); + + return 0; +} diff --git a/lessons/01-introduction/variables.rs b/lessons/01-introduction/variables.rs new file mode 100644 index 0000000..3350568 --- /dev/null +++ b/lessons/01-introduction/variables.rs @@ -0,0 +1,18 @@ +#![allow(unused_variables)] +#![allow(unused_assignments)] + +fn main() { + let x = 40; // inferred type + let y: i32 = 100; // specified type + + { + let x = 40 + 2; // shadowing + println!("x is {}", x); // prints 42 + } + + // x = 0; // compilation error, variables are by default immutable + let mut x = 40; // declare as mutable + x = 0; // now we can reassign + + x += 1; // x = x + 1 +} diff --git a/lessons/01_introduction/a_taste_of_rust-introductory_slides/a-taste-of-rust/index.html b/lessons/01_introduction/a_taste_of_rust-introductory_slides/a-taste-of-rust/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/01_introduction/a_taste_of_rust-introductory_slides/a-taste-of-rust/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
        +

        Welcome to Zola!

        +

        + You're seeing this page because we couldn't find a template to render. +

        +

        + To modify this page, create a page.html file in the templates directory or + install a theme. +
        + You can find what variables are available in this template in the documentation. +

        +
        + + + + diff --git a/lessons/02-ownership/aliasing-xor-mutability/Cargo.toml b/lessons/02-ownership/aliasing-xor-mutability/Cargo.toml new file mode 100644 index 0000000..c4044ef --- /dev/null +++ b/lessons/02-ownership/aliasing-xor-mutability/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "aliasing_xor_mutability" +version = "0.1.0" +edition = "2021" diff --git a/lessons/02-ownership/aliasing-xor-mutability/src/main.rs b/lessons/02-ownership/aliasing-xor-mutability/src/main.rs new file mode 100644 index 0000000..d6fed8b --- /dev/null +++ b/lessons/02-ownership/aliasing-xor-mutability/src/main.rs @@ -0,0 +1,39 @@ +fn next_int() -> i32 { + 42 +} + +struct Data(i32); +impl Data { + fn new() -> Self { + Self(0) + } + + fn read(&self) -> i32 { self.0 } + + fn write(&mut self, n: i32) { self.0 = n } +} + +fn thread1(shared_data: &mut Data) { + loop { + shared_data.write(next_int()); + } +} + +fn thread2(shared_data: &Data) { + loop { + println!("{}", shared_data.read()); + } +} + +fn main() { + let mut shared_data = Data::new(); + + std::thread::scope(|s| { + let t1 = s.spawn(|| { + thread1(&mut shared_data); + }); + let t2 = s.spawn(|| { + thread2(&shared_data); + }); + }); +} \ No newline at end of file diff --git a/lessons/02-ownership/dont_panic/dont_panic.html b/lessons/02-ownership/dont_panic/dont_panic.html new file mode 100644 index 0000000..3963ba2 --- /dev/null +++ b/lessons/02-ownership/dont_panic/dont_panic.html @@ -0,0 +1,3903 @@ + + + + + + + + + + + + + + + + +
        + +
        +
        + +
        +

        Don't panic

        +

        + ...or how should your Rust program behave when faced a critical + error. +

        +
        +
        +
        +

        + A situation which unfortunately happens too often... +

        +
        +              // This function returns Order, so we are forced to
        +                  return
        +                // an Order even for incorrect inputs.
        +                fn
        +                create_order(num_dishes: usize)
        +                -> Order {
        +                if num_dishes <
        +                Order::MAXIMUM_NUM_DISHES {
        +                Ok(Order::new(num_dishes)) } else {
        +                // ??? Order::INVALID ???
        +                } }
        +              
        +            
        +
        +
        +
        +

        LET'S PANIC!

        +
        +              // This function returns Order, so we are forced to
        +                  return
        +                // an Order even for incorrect inputs.
        +                fn
        +                create_order(num_dishes: usize)
        +                -> Order {
        +                if num_dishes <
        +                Order::MAXIMUM_NUM_DISHES {
        +                Ok(Order::new(num_dishes)) } else {
        +                panic!("Too many dishes for a single Order")
        +                // This either unwinds the stack or aborts the program
        +                  immediately.
        +                // (configurable in Cargo.toml of your project)
        +                } }
        +              
        +            
        +
        +
        +
        +

        + Hmm, maybe let's reconsider this... +

        +
        +              /// Error signifying that there are too many dishes to fit in
        +                  an Order.
        +                struct
        +                TooManyDishes;
        +
        +                // This function returns Result, so that we are not forced to
        +                  return
        +                // an Order for incorrect inputs - we just return Err.
        +                fn
        +                create_order(num_dishes: usize)
        +                ->
        +                Result<Order,
        +                TooManyDishes> {
        +                if num_dishes <
        +                Order::MAXIMUM_NUM_DISHES {
        +                Ok(Order::new(num_dishes)) } else {
        +                Err(TooManyDishes) } }
        +              
        +            
        +
        +
        +
        +

        + Another common case - Option/Result +

        +
        +              struct
        +                DivisionByZero;
        +
        +                fn
        +                div(dividend:
        +                i32, divisor:
        +                i32)
        +                ->
        +                Result<i32, DivisionByZero> {
        +                if divisor ==
        +                0 {
        +                // It is idiomatic to return errors after failed checks early
        +                  in an imperative way, using explicit `return`.
        +                return
        +                Err(DivisionByZero) }
        +
        +                // It is idiomatic to have the "happy path" (the
        +                  no-errors scenario) linear and using functional syntax.
        +                Ok(dividend /
        +                divisor) } fn
        +                main() {
        +                let
        +                res:
        +                Result<i32, DivisionByZero> =
        +                div(2137, 42);
        +
        +                // We are 100% sure division by 42 can't fail, so
        +                  let's use this shorthand.
        +                let
        +                quotient = res.unwrap();
        +
        +                // This is equivalent to:
        +                let
        +                quotient =
        +                match res {
        +                Ok(x) =>
        +                x, Err(err)
        +                => panic!("called `Result::unwrap()` on an `Err` value:
        +                  {:?}", err), } }
        +              
        +            
        +
        +
        +
        +

        + Let's encode more guarantees in the type system! +

        +
        +              use std::num::NonZeroI32;
        +
        +                fn
        +                div(dividend:
        +                i32, divisor: NonZeroI32)
        +                ->
        +                i32 { dividend / divisor
        +                // Nothing can get broken here!
        +                }
        +                fn
        +                main() {
        +                // let quotient = div(2137, 42); // This would not type
        +                  check, because 42 is not NonZeroI32.
        +
        +                // We have to create a NonZeroI32 instance:
        +                let
        +                non_zero_divisor_opt:
        +                Option<NonZeroI32> =
        +                NonZeroI32::new(42);
        +
        +                // We are 100% sure 42 is not 0, so let's use this
        +                  shorthand.
        +                let
        +                non_zero_divisor =
        +                non_zero_divisor_opt.unwrap();
        +
        +                // This is equivalent to:
        +                let
        +                non_zero_divisor =
        +                match non_zero_divisor_opt {
        +                Some(x) =>
        +                x, None =>
        +                panic!("called `Option::unwrap()` on a `None` value"), }
        +
        +                let
        +                quotient =
        +                div(2137, non_zero_divisor); }
        +              
        +            
        +
        +
        +
        +

        + But wait, we ended up with an unwrap() anyway. Did we + then improve at all? +

        +

        + Actually, yes. Now, the function (here: div()) with + some (possibly complex) logic only accepts (so + that the compiler verifies that in compile-time) valid arguments. + This way, the function's code can be simpler (no + invalid-input-related error handling). Also, it's easier to + convince yourself that your number is nonzero that to make sure + that it upholds all guarantees required in the docs of the + function containing logic. +

        +
        +
        +
        +

        + To panic or not to panic +

        +

        Don't panic:

        +
          +
        • + if the failure is caused by bad user input - you don't want to + open up a highway for DoS attackers, do you? +
        • +
        • + if the failure only affects some task and not the program in + general, e.g. when the server returned bad data for a request of + one of the users; others are unaffected; +
        • +
        • + if the failure is recoverable (there is a reasonable action to + be done in such situation, e.g. give user the default value when + the server can't be queried for the actual value); +
        • +
        +
        +
        +
        +

        + To panic or not to panic +

        +

        Do panic:

        +
          +
        • + if the failure is for sure caused by a bug in your code. It + makes sense to inform the whole world that you wrote deficient + software, by yelling at them. More seriously, this shortens the + feedback loop and bugs are fixed earlier, instead of silently + damaging production; +
        • +
        • + if the failure is not recoverable (there is no hope, the program + is broken, R.I.P., only the famous + restart could help here); +
        • +
        +
        +
        +
        +
        +
        +
        + + + diff --git a/lessons/02-ownership/dont_panic/dont_panic.pdf b/lessons/02-ownership/dont_panic/dont_panic.pdf new file mode 100644 index 0000000000000000000000000000000000000000..09281518fdacc4af8791a3b6eb37ccc0f5a01857 GIT binary patch literal 45178 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 literal 0 HcmV?d00001 diff --git a/lessons/02-ownership/index.html b/lessons/02-ownership/index.html new file mode 100644 index 0000000..70b5b34 --- /dev/null +++ b/lessons/02-ownership/index.html @@ -0,0 +1,515 @@ + + + + + + + + Rust course + + + + + + + + + + + + + +

        + +
        + + +
        + +
        + +
        +
        +
          +
          +
          + +
          + +

          Ownership Model

          +

          + 2024-10-10 (last edit: 2024-10-08) +

          +

          Why all the fuss?

          +

          Even if you've never seen Rust code before, chances are you still heard the term borrow checker or something about Rust's ownership. Indeed, Rust's ownership model lies at the very core of its uniqueness. But to fully understand it and appreciate it, let's first take a look at how memory management is handled in most popular languages.

          +
            +
          • +

            Garbage Collection - in many high-level programming languages, like Java, Haskell or Python, memory management is done fully by the language, relieving the programmer from this burden. This prevents memory leaks and memory related errors (like use after free), but does come at a cost - there is a runtime overhead, both memory and performance wise, caused by the constantly running garbage collection algorithms and the programmer usually has very little control over when the garbage collection takes place. Also, garbage collection does not prevent concurrency-related errors, such as data races, in any way.

            +
          • +
          • +

            Mind your own memory - in low-level languages and specific ones like C++, performance comes first so we cannot really afford to run expansive bookkeeping and cleaning algorithms. Most of these languages compile directly to machine code and have no language-specific runtime environment. That means that the only place where memory management can happen is in the produced code. While compilers insert these construction and destruction calls for stack allocated memory, it generally requires a lot of discipline from the programmer to adhere to good practices and patterns to avoid as many memory related issues as possible and one such bug can be quite deadly to the program and a nightmare to find and fix. These languages basically live by the "your memory, your problem" mantra.

            +
          • +
          +

          And then we have Rust. Rust is a systems programming language and in many ways it's akin to C++ - it's basically low-level with many high-level additions. But unlike C++, it doesn't exactly fall into either of the categories described above, though it's way closer to the second one. It performs no additional management at runtime, but instead imposes a set of rules on the code, making it easier to reason about and thus check for its safety and correctness at compile time - these rules make up Rust's ownership model.

          +

          In a way, programming in Rust is like pair-programming with a patient and very experienced partner. Rust's compiler will make sure you follow all the good patterns and practices (by having them ingrained in the language itself) and very often even tell you how to fix the issues it finds.

          +

          Disclaimer: when delving deeper into Rust below we will make heavy use of concepts like scopes, moving data, stack and heap, which should have been introduced as part of the C++ course. If you need a refresher of any of these, it's best to do so now, before reading further.

          +

          Start with the basics - ownership

          +

          In the paragraph above we mentioned a set of rules that comprise Rust's ownership model. The book starts off with the following three as its very foundation:

          +
            +
          1. +

            Each value in Rust is tied to a specific variable - we call that variable its owner.

            +
          2. +
          3. +

            There can only be one owner at a time.

            +
          4. +
          5. +

            When the owner goes out of scope, the value will be destroyed (or in Rust terms - dropped).

            +
          6. +
          +

          The third point might make you think about C++ and its automatic storage duration. We will later see that, while very similar at first, Rust expands on these mechanics quite a bit. The following code illustrates the basic version of this:

          +
          {
          +    let a: i32 = 5; // allocation on the stack, 'a' becomes an owner
          +
          +    // do some stuff with 'a'
          +
          +} // 'a', the owner, goes out of scope and the value is dropped
          +
          +

          So far, so good. Variables are pushed onto the stack when they enter the scope and destroyed during stack unwinding that happens upon leaving their scope. However, allocating and deallocating simple integers doesn't impress anybody. Let's try something more complex:

          +
          {
          +    let s = String::from("a string"); // 's' is allocated on the stack, while its contents ("a string")
          +                                      // are allocated on the heap. 's' is the owner of this String object.
          +
          +    // do some stuff with 's'
          +
          +} // 's', the owner, goes out of scope and the String is dropped, its heap allocated memory freed
          +
          +

          If you recall the RAII (Resource Acquisition Is Initialization) pattern from C++, the above is basically the same thing. We go two for two now in the similarity department, so... is Rust really any different then? There is a part of these examples that we skipped over - actually doing something with the values.

          +

          Moving around is fun

          +

          Let's expand on the last example. The scoping is not really important for that one, so we don't include it here.

          +
          let s = String::from("a string"); // same thing, 's' is now an owner
          +
          +let s2 = s; // easy, 's2' becomes another owner... right?
          +
          +println!("And the contents are: {}", s); // this doesn't work, can you guess why?
          +
          +

          At first glance everything looks great. If we write this code (well, an equivalent of it) in basically any other popular language, it will compile no issue - but it does not here and there's a good reason why.

          +

          To understand what's happening, we have to consult the rules again, rule 2 in particular. It says that there can only be one owner of any value at a given time. So, s and s2 cannot own the same object. Okay, makes sense, but what is happening in this line then - let s2 = s;? Experience probably tells you that s just gets copied into s2, creating a new String object. That would result in each variable owning its very own instance of the string and each instance having exactly one owner. Sounds like everyone should be happy now, but wait - in that case the last line should work no issue, right? But it doesn't, so can't be a copy. Let's see now what the compiler actually has to say:

          +
          error[E0382]: borrow of moved value: `s`
          + --> src/main.rs:6:42
          +  |
          +2 |     let s = String::from("a string");
          +  |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
          +3 |
          +4 |     let s2 = s;
          +  |              - value moved here
          +5 |
          +6 |     println!("And the contents are: {}", s);
          +  |                                          ^ value borrowed here after move
          +
          +

          "value moved here" - gotcha! So s is being moved to s2, which also means that s2 now becomes the new owner of the string being moved and s cannot be used anymore. In Rust, the default method of passing values around is by move, not by copy. While it may sound a bit odd at first, it actually has some very interesting implications. But before we get to them, let's fix our code, so it compiles now. To do so, we have to explicitly tell Rust to make a copy by invoking the clone method:

          +
          let s = String::from("a string"); // 's' is an owner
          +
          +let s2 = s.clone(); // 's2' now contains its own copy
          +
          +println!("And the contents are: {}", s); // success!
          +
          +

          The compiler is happy now and so are we. The implicit move takes some getting used to, but the compiler is here to help us. Now, let's put the good, old C++ on the table again and compare the two lines:

          +
          +

          let s2 = s; is equivalent to auto s2 = std::move(s);

          +

          let s2 = s.clone() is equivalent to auto s2 = s

          +
          +

          There are a few important things to note here:

          +
            +
          • +

            Making a copy is oftentimes not cheap. Memory needs to be allocated and copied, and a call to the system has to be made. We should prefer to move things as much as possible to avoid this cost - in C++ we have a myriad of language features like std::move and r-references to achieve this. Every programmer worth their salt needs to be well versed in all of them to write efficient C++ code and simply forgetting one move can lead to significant performance loss (and this happens to even the most senior devs ever existing, let's not pretend). On the contrary, in Rust you need to make an effort to make a copy and that makes you very aware of the cost you're paying - something that we'll see quite a lot of in the language. Also, if you forget a clone there's no harm done - it just won't compile!

            +
          • +
          • +

            Hidden in all of this is another nice thing Rust gives us. In C++, nothing prevents you from using variables after they've been moved from, leading to unexpected errors in a more complex code. In Rust, that variable (in our case s) simply becomes invalid and the compiler gives us a nice error about it.

            +
          • +
          +

          But what about ints?

          +

          A good question to ask. Copying primitives is cheap. And it's not convenient for the programmer to have to always write .clone() after every primitive. If we take a look at the error from the previous example:

          +
          move occurs because `s` has type `String`, which does not implement the `Copy` trait`
          +
          +

          It says that s was moved because the String type doesn't have the Copy trait. We will talk about traits more in depth in the future lessons, but what this basically means is that String is not specified to be copied by default. All primitive types (i32, bool, f64, char, etc.) and tuples consisting only of primitive types implement the Copy trait.

          +

          Exercise

          +

          How to fix that code?

          +
          fn count_animals(num: u32, animal: String) {
          +    println!("{} {} ...", num, animal);
          +}
          +
          +fn main() {
          +  let s = String::from("sheep");
          +
          +  count_animals(1, s);
          +  count_animals(2, s);
          +  count_animals(3, s);
          +}
          +
          +

          Let's borrow some books

          +

          We now know how to move things around and how to clone them if moving is not possible. But what if making a copy is unnecessary - maybe we just want to let someone look at our resource and keep on holding onto it once they're done. Consider the following example:

          +
          fn read_book(book: String) {
          +    println!("[Reading] {}", book);
          +}
          +
          +fn main() {
          +  let book = String::from("Merry lived in a big old house. The end.");
          +
          +  read_book(book.clone());
          +
          +  println!("Book is still there: {}", book);
          +}
          +
          +

          Cloning is pretty excessive here. Imagine recommending a book to your friend and instead of lending it to them for the weekend, you scan it and print an exact copy. Not the best way to go about it, is it? Thankfully, Rust allows us to access a resource without becoming an owner through the use of references and the & operator. This is called a borrow.

          +

          The adjusted code should look like this:

          +
          fn read_book(book: &String) {
          +    println!("[Reading] {}", book);
          +}
          +
          +fn main() {
          +  let book = String::from("Merry lived in a big old house. The end.");
          +
          +  read_book(&book);
          +
          +  println!("Book is still there: {}", book);
          +}
          +
          +

          As with everything, references are too, by default, immutable, which means that the read_book function is not able to modify that book passed into it. We can also borrow something mutably by specifying it both in the receiving function signature and the place it gets called. Maybe you want to have your book signed by its author?

          +
          fn sign_book(book: &mut String) {
          +    book.push_str(" ~ Arthur Author");
          +}
          +
          +fn main() {
          +  // note that the book has to be marked as mutable in the first place
          +  let mut book = String::from("Merry lived in a big old house. The end.");
          +
          +  sign_book(&mut book); // it's always clear when a parameter might get modified
          +
          +  println!("{}", book); // book is now signed
          +}
          +
          +

          Pretty neat, but doesn't seem that safe right now. Let's try to surprise our friend:

          +
          fn erase_book(book: &mut String) {
          +    book.clear();
          +}
          +
          +fn read_book(book: &String) {
          +    println!("[Reading] {}", book);
          +}
          +
          +fn main() {
          +  let mut book = String::from("Merry lived in a big old house. The end.");
          +
          +  let r = &book; // an immutable borrow
          +
          +  erase_book(&mut book); // a mutable borrow
          +
          +  read_book(r); // would be pretty sad to open a blank book when it was not
          +                // what we borrowed initially
          +
          +  println!("{}", book);
          +}
          +
          +

          Fortunately for us (and our poor friend just wanting to read), the compiler steps in and doesn't let us do that, printing the following message:

          +
          error[E0502]: cannot borrow `book` as mutable because it is also borrowed as immutable
          +  --> src/main.rs:14:14
          +   |
          +12 |   let r = &book; // an immutable borrow
          +   |           ----- immutable borrow occurs here
          +13 |
          +14 |   erase_book(&mut book); // a mutable borrow
          +   |              ^^^^^^^^^ mutable borrow occurs here
          +15 |
          +16 |   read_book(r); // would be pretty sad to open a blank book when it was not
          +   |             - immutable borrow later used here
          +
          +

          This is where the famous borrow checker comes in. To keep things super safe, Rust clearly states what can and cannot be done with references and tracks their lifetimes. Exactly one of the following is always true for references to a given resource:

          +
            +
          • +

            There exists only one mutable reference and no immutable references, or

            +
          • +
          • +

            There is any number of immutable references and no mutable ones.

            +
          • +
          +

          You may notice a parallel to the readers - writers problem from concurrent programming. In fact, the way Rust's borrow checker is designed lends itself incredibly well to preventing data race related issues.

          +

          Dangling references

          +

          Rust also checks for dangling references. If we try to compile the following code:

          +
          fn main() {
          +    let reference_to_nothing = dangle();
          +}
          +
          +fn dangle() -> &String {
          +    let s = String::from("hello");
          +
          +    &s
          +}
          +
          +

          we will get an adequate error:

          +
          error[E0106]: missing lifetime specifier
          + --> src/main.rs:5:16
          +  |
          +5 | fn dangle() -> &String {
          +  |                ^ expected named lifetime parameter
          +  |
          +  = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
          +help: consider using the `'static` lifetime
          +  |
          +5 | fn dangle() -> &'static String {
          +  |                ^^^^^^^^
          +
          +

          The message above suggests specifing a lifetime for the returned string. In Rust, the lifetime of each variable is also a part of its type, but we will talk more about it later.

          +

          Exercise

          +

          Our previous solution using clone() was pretty inefficient. How should this code look now?

          +
          fn count_animals(num: u32, animal: String) {
          +    println!("{} {} ...", num, animal);
          +}
          +
          +fn main() {
          +  let s = String::from("sheep");
          +
          +  count_animals(1, s.clone());
          +  count_animals(2, s.clone());
          +  count_animals(3, s); // we could've ommitted the clone() here. Why?
          +}
          +
          +

          Everyone gets a slice

          +

          The last part of working with references that we will cover in this lesson are slices. A slice in Rust is a view over continuous data. Let us start with a string slice - the &str type.

          +

          Note: for the purposes of these examples we assume we are working with ASCII strings. More comprehensive articles on handling strings are linked at the end of this lesson.

          +

          To create a string slice from the String object s, we can simply write:

          +
          let slice = &s[1..3]; // creates a slice of length 2, starting with the character at index 1
          +
          +

          This makes use of the & operator and Rust's range notation to specify the beginning and end of the slice. Thus, we can also write:

          +
          let slice = &s[2..];    // everything from index 2 till the end
          +let slice = &s[..1];    // only the first byte
          +let slice = &s[..];     // the whole string as a slice
          +let slice = s.as_str(); // also the whole string
          +
          +

          You might have noticed that we always built String values using the from() method and never actually used the string literals directly. What type is a string literal then? Turns out it's the new string slice we just learned about!

          +
          let slice: &str = "string literal";
          +
          +

          In fact, it makes a lot sense - string literals, after all, are not allocated on the heap, but rather placed in a special section of the resulting binary. It's only natural we just reference that place with a slice.

          +

          Slices can also be taken from arrays:

          +
          let array: [i32; 4] = [42, 10, 5, 2]; // creates an array of four 32 bit integers
          +let slice: &[i32] = &array[1..3];     // results in a slice [10, 5]
          +
          +

          Exercise

          +

          Can this code still be improved from the previous version utilizing references? Think about the signature of count_animals.

          +
          fn count_animals(num: u32, animal: &String) {
          +    println!("{} {} ...", num, animal);
          +}
          +
          +fn main() {
          +  let s = String::from("sheep");
          +
          +  count_animals(1, &s);
          +  count_animals(2, &s);
          +  count_animals(3, &s);
          +}
          +
          +

          Further reading

          + +

          Assignment 1 (graded)

          +

          ordering in Van Binh

          +

          Deadline: 16.10.2024 23:59

          + + +
          +
          + + + + +
          + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/02-ownership/string_formatting/string_formatting.html b/lessons/02-ownership/string_formatting/string_formatting.html new file mode 100644 index 0000000..d891819 --- /dev/null +++ b/lessons/02-ownership/string_formatting/string_formatting.html @@ -0,0 +1,3842 @@ + + + + + + + + + + + + + + + + +
          + +
          +
          + +
          +

          String formatting

          +

          ...printf(), sprintf() equivalents & related topics.

          +
          +
          +
          +

          + Simplest possible output from Rust program +

          +
          +              fn
          +                main() {
          +                println!("Hello stdout!"); eprintln!("Hello stderr!"); }
          +              
          +            
          +
          +
          +
          +

          + Formatted output (using Display trait) +

          +
          +              fn
          +                agriculture() {
          +                let
          +                num_animals =
          +                42_usize;
          +                let
          +                animal_name =
          +                "ducks";
          +
          +                println!("We have {} {} in our farm.", num_animals, animal_name);
          +
          +                let
          +                s:
          +                String =
          +                format!(
          +                "Nothing is better than {0} {2}, except for {1}
          +                  {2},", num_animals, num_animals +
          +                1, animal_name );
          +
          +                // Minimal assert.
          +                assert!(num_animals >=
          +                42);
          +                // assert with a custom panic message.
          +                assert!( num_animals >=
          +                42,
          +                "Too few animals in our farm :( - only {} {}", num_animals, animal_name ); }
          +              
          +            
          +
          +
          +
          +

          + Formatted output (using Debug trait) +

          +
          +              fn
          +                agriculture() {
          +                let
          +                animals: &[&str] = &["Azor",
          +                "Mućka"];
          +
          +                // Does not compile: &[&str] does not implement
          +                  Display.
          +                // println!("We have the following animals in our farm:
          +                  {}", animals);
          +
          +                // Concise printing for debug purposes:
          +                println!("We have the following animals in our farm:
          +                  {:?}", animals);
          +                // Outputs:
          +                // We have the following animals in our farm:
          +                  ["Azor", "Mućka"]
          +
          +                // Pretty-printing for debug purposes:
          +                println!("We have the following animals in our farm:
          +                  {:#?}", animals);
          +                // Outputs:
          +                // We have the following animals in our farm: [
          +                // "Azor",
          +                // "Mućka"
          +                // ]
          +                }
          +              
          +            
          +

          Various ways to panic

          +
          +              fn
          +                panicking_is_fun() {
          +                panic!("A general panic."); assert!(false,
          +                "An assertion failed.");
          +
          +                unimplemented!("This code is not implemented."); todo!("This code is not YET implemented - it's going to
          +                  change.");
          +
          +                unreachable!("We should never reach this line of code!"); }
          +              
          +            
          +
          +
          +
          +

          + Memory backing considerations +

          +
          +              fn
          +                agriculture() {
          +                let
          +                animals: &[&str] = &["Azor",
          +                "Mućka"];
          +
          +                let
          +                animals: [&str; 2] = ["Azor", "Mućka"];
          +                let
          +                animals: &[&str] = &animals;
          +
          +                let
          +                animals:
          +                Vec<&str> = vec!["Azor", "Mućka"];
          +
          +                static ANIMALS: [&str; 2] = ["Azor", "Mućka"];
          +                static ANIMALS_SLICE:
          +                &[&str] = &ANIMALS;
          +
          +                let
          +                animals:
          +                Vec<&str> = vec!["Azor", "Mućka"];
          +                let
          +                animals_slice:
          +                &[&str] = &animals;
          +
          +                let
          +                animals:
          +                Vec<String> = vec!["Azor".into(),
          +                "Mućka".into()]; }
          +              
          +            
          +
          +
          +
          +

          + Memory backing considerations - with hints +

          +
          +              fn
          +                agriculture() {
          +                let
          +                animals: &[&str] = &["Azor",
          +                "Mućka"];
          +                // stack-allocated stack-backed slice.
          +
          +                // stack-allocated array (of statically-allocated
          +                  strings).
          +                let
          +                animals: [&str; 2] = ["Azor", "Mućka"];
          +                let
          +                animals: &[&str] = &animals;
          +                // stack-allocated stack-backed slice.
          +
          +                let
          +                animals:
          +                Vec<&str> = vec!["Azor", "Mućka"];
          +                // stack-allocated heap-backed slice.
          +
          +                static ANIMALS: [&str; 2] = ["Azor", "Mućka"];
          +                // statically-allocated array.
          +                static ANIMALS_SLICE:
          +                &[&str] = &ANIMALS;
          +                // statically-allocated statically-backed slice.
          +
          +                let
          +                animals:
          +                Vec<&str> = vec!["Azor", "Mućka"];
          +                // stack-allocated heap-backed Vec.
          +                let
          +                animals_slice:
          +                &[&str] = &animals;
          +                // stack-allocated heap-backed slice.
          +
          +                // stack-allocated heap-backed Vec of heap-allocated
          +                  strings.
          +                let
          +                animals:
          +                Vec<String> = vec!["Azor".into(),
          +                "Mućka".into()]; }
          +              
          +            
          +
          +
          +
          +
          +
          +
          + + + diff --git a/lessons/02-ownership/string_formatting/string_formatting.pdf b/lessons/02-ownership/string_formatting/string_formatting.pdf new file mode 100644 index 0000000000000000000000000000000000000000..23ab2347c0689066af02bccf18a89c0bd5391681 GIT binary patch literal 33439 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 literal 0 HcmV?d00001 diff --git a/lessons/02_ownership/dont_panic/dont-panic/index.html b/lessons/02_ownership/dont_panic/dont-panic/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/02_ownership/dont_panic/dont-panic/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
          +

          Welcome to Zola!

          +

          + You're seeing this page because we couldn't find a template to render. +

          +

          + To modify this page, create a page.html file in the templates directory or + install a theme. +
          + You can find what variables are available in this template in the documentation. +

          +
          + + + + diff --git a/lessons/02_ownership/string_formatting/string-formatting/index.html b/lessons/02_ownership/string_formatting/string-formatting/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/02_ownership/string_formatting/string-formatting/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
          +

          Welcome to Zola!

          +

          + You're seeing this page because we couldn't find a template to render. +

          +

          + To modify this page, create a page.html file in the templates directory or + install a theme. +
          + You can find what variables are available in this template in the documentation. +

          +
          + + + + diff --git a/lessons/03-data-types/data_types.rs b/lessons/03-data-types/data_types.rs new file mode 100644 index 0000000..181acea --- /dev/null +++ b/lessons/03-data-types/data_types.rs @@ -0,0 +1,88 @@ +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct Position(i32, i32); // tuple struct + +// Could Hero derive the Copy trait? +#[derive(Clone, Debug, Eq, PartialEq)] +struct Hero { + name: String, + level: u32, + experience: u32, + position: Position, +} + +// we can add methods to structs using the 'impl' keyword +impl Hero { + // static method (in Rust nomenclature: "associated function") + fn new(name: String) -> Hero { + Hero { + name, + level: 1, + experience: 0, + position: Position(0, 0), + } + } +} + +// multiple impl blocks are possible for one struct +impl Hero { + // instance method, first argument (self) is the calling instance + fn distance(&self, pos: Position) -> u32 { + // shorthand to: `self: &Self` + // field `i` of a tuple or a tuple struct can be accessed through 'tuple.i' + (pos.0 - self.position.0).unsigned_abs() + (pos.1 - self.position.1).unsigned_abs() + } + + // mutable borrow of self allows to change instance fields + fn level_up(&mut self) { + // shorthand to: `self: &mut Self` + self.experience = 0; + self.level += 1; + } + + // 'self' is not borrowed here and will be moved into the method + fn die(self) { + // shorthand to: `self: Self` + println!( + "Here lies {}, a hero who reached level {}. RIP.", + self.name, self.level + ); + } +} + +fn main() { + // Calling associated functions requires scope (`::`) operator. + let mut hero: Hero = Hero::new(String::from("Ferris")); + hero.level_up(); // 'self' is always passed implicitly + + // fields other than 'name' will be the same as in 'hero' + let steve = Hero { + name: String::from("Steve The Normal Guy"), + ..hero + }; + + assert_eq!(hero.level, steve.level); + + let mut twin = hero.clone(); + + // we can compare Hero objects because it derives the PartialEq trait + assert_eq!(hero, twin); + twin.level_up(); + assert_ne!(hero, twin); + hero.level_up(); + assert_eq!(hero, twin); + + // we can print out a the struct's debug string with '{:?}' + println!("print to stdout: {:?}", hero); + + hero.die(); // 'hero' is not usable after this invocation, see the method's definiton + + // the dbg! macro prints debug strings to stderr along with file and line number + // dbg! takes its arguments by value, so better borrow them not to have them + // moved into dbg! and consumed. + dbg!("print to stderr: {}", &twin); + + let pos = Position(42, 0); + let dist = steve.distance(pos); // no clone here as Position derives the Copy trait + println!("{:?}", pos); + assert_eq!(dist, 42); +} diff --git a/lessons/03-data-types/enums.c b/lessons/03-data-types/enums.c new file mode 100644 index 0000000..0b20f64 --- /dev/null +++ b/lessons/03-data-types/enums.c @@ -0,0 +1,35 @@ +#include + +enum shirt_size { + small, + medium, + large, + xlarge +}; + +void print_size(enum shirt_size size) { + printf("my size is "); + switch (size) { + case small: + printf("small"); + break; + case medium: + printf("medium"); + break; + case large: + printf("large"); + break; + case xlarge: + printf("xlarge"); + break; + default: + printf("unknown"); + break; + } + printf("\n"); +} + +int main() { + enum shirt_size my_size = medium; + print_size(my_size); +} diff --git a/lessons/03-data-types/enums.rs b/lessons/03-data-types/enums.rs new file mode 100644 index 0000000..ceab783 --- /dev/null +++ b/lessons/03-data-types/enums.rs @@ -0,0 +1,28 @@ +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(dead_code)] + +#[derive(Debug)] +enum NamedSize { + Small, + Medium, + Large, + XL, +} + +#[derive(Debug)] +enum ShirtSize { + Named(NamedSize), + Numeric(u32), +} + +fn main() { + println!( + "Isn't it strange that some clothes' sizes are adjectives like {:?},", + ShirtSize::Named(NamedSize::Small) + ); + println!( + "but sometimes they are numbers like {:?}?", + ShirtSize::Numeric(42) + ); +} diff --git a/lessons/03-data-types/index.html b/lessons/03-data-types/index.html new file mode 100644 index 0000000..caf3c23 --- /dev/null +++ b/lessons/03-data-types/index.html @@ -0,0 +1,797 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
          + + +
          + +
          + +
          +
          +
            +
            +
            + +
            + +

            Data Types

            +

            + 2024-10-17 (last edit: 2024-10-17) +

            +

            Aggregating data

            +

            Below is a compact overview of Rust's structs

            +
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            +struct Position(i32, i32); // tuple struct
            +
            +// Could Hero derive the Copy trait?
            +#[derive(Clone, Debug, Eq, PartialEq)]
            +struct Hero {
            +    name: String,
            +    level: u32,
            +    experience: u32,
            +    position: Position,
            +}
            +
            +// we can add methods to structs using the 'impl' keyword
            +impl Hero {
            +    // static method (in Rust nomenclature: "associated function")
            +    fn new(name: String) -> Hero {
            +        Hero {
            +            name,
            +            level: 1,
            +            experience: 0,
            +            position: Position(0, 0),
            +        }
            +    }
            +}
            +
            +// multiple impl blocks are possible for one struct
            +impl Hero {
            +    // instance method, first argument (self) is the calling instance
            +    fn distance(&self, pos: Position) -> u32 {
            +        // shorthand to: `self: &Self`
            +        // field `i` of a tuple or a tuple struct can be accessed through 'tuple.i'
            +        (pos.0 - self.position.0).unsigned_abs() + (pos.1 - self.position.1).unsigned_abs()
            +    }
            +
            +    // mutable borrow of self allows to change instance fields
            +    fn level_up(&mut self) {
            +        // shorthand to: `self: &mut Self`
            +        self.experience = 0;
            +        self.level += 1;
            +    }
            +
            +    // 'self' is not borrowed here and will be moved into the method
            +    fn die(self) {
            +        // shorthand to: `self: Self`
            +        println!(
            +            "Here lies {}, a hero who reached level {}. RIP.",
            +            self.name, self.level
            +        );
            +    }
            +}
            +
            +fn main() {
            +    // Calling associated functions requires scope (`::`) operator.
            +    let mut hero: Hero = Hero::new(String::from("Ferris"));
            +    hero.level_up(); // 'self' is always passed implicitly
            +
            +    // fields other than 'name' will be the same as in 'hero'
            +    let steve = Hero {
            +        name: String::from("Steve The Normal Guy"),
            +        ..hero
            +    };
            +
            +    assert_eq!(hero.level, steve.level);
            +
            +    let mut twin = hero.clone();
            +
            +    // we can compare Hero objects because it derives the PartialEq trait
            +    assert_eq!(hero, twin);
            +    twin.level_up();
            +    assert_ne!(hero, twin);
            +    hero.level_up();
            +    assert_eq!(hero, twin);
            +
            +    // we can print out a the struct's debug string with '{:?}'
            +    println!("print to stdout: {:?}", hero);
            +
            +    hero.die(); // 'hero' is not usable after this invocation, see the method's definiton
            +
            +    // the dbg! macro prints debug strings to stderr along with file and line number
            +    // dbg! takes its arguments by value, so better borrow them not to have them
            +    // moved into dbg! and consumed.
            +    dbg!("print to stderr: {}", &twin);
            +
            +    let pos = Position(42, 0);
            +    let dist = steve.distance(pos); // no clone here as Position derives the Copy trait
            +    println!("{:?}", pos);
            +    assert_eq!(dist, 42);
            +}
            +
            +
            +

            (Download the source code for this example: data_types.rs)

            +

            Enums

            +

            It is often the case that we want to define a variable that can only take +a certain set of values and the values are known up front. In C you can use an enum for this.

            +
            #include <stdio.h>
            +
            +enum shirt_size {
            +    small,
            +    medium,
            +    large,
            +    xlarge
            +};
            +
            +void print_size(enum shirt_size size) {
            +    printf("my size is ");
            +    switch (size) {
            +        case small:
            +            printf("small");
            +            break;
            +        case medium:
            +            printf("medium");
            +            break;
            +        case large:
            +            printf("large");
            +            break;
            +        case xlarge:
            +            printf("xlarge");
            +            break;
            +        default:
            +            printf("unknown");
            +            break;
            +    }
            +    printf("\n");
            +}
            +
            +int main() {
            +    enum shirt_size my_size = medium;
            +    print_size(my_size);
            +}
            +
            +
            +

            (Download the source code for this example: enums.c)

            +

            However, in C enums are just integers. Nothing prevents us from writing

            +
            int main() {
            +    enum shirt_size my_size = 666;
            +    print_size(my_size);
            +}
            +
            +

            C++ introduces enum classes which are type-safe. Legacy enums are also somewhat safer than in C (same code as above):

            +
            <source>:27:31: error: invalid conversion from 'int' to 'shirt_size' [-fpermissive]
            +   27 |     enum shirt_size my_size = 666;
            +      |                               ^~~
            +      |                               |
            +      |                               int
            +
            +

            Some programming languages (especially functional ones) allow programmers to define +enums which carry additional information. Such types are usually called tagged unions +or algebraic data types.

            +

            In C++ we can use union with an enum tag to define it:

            +
            #include <iostream>
            +
            +// Taken from: https://en.cppreference.com/w/cpp/language/union
            +
            +// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE),
            +// and three variant members (c, i, d)
            +struct S
            +{
            +    enum{CHAR, INT, DOUBLE} tag;
            +    union
            +    {
            +        char c;
            +        int i;
            +        double d;
            +    };
            +};
            +
            +void print_s(const S& s)
            +{
            +    switch(s.tag)
            +    {
            +        case S::CHAR: std::cout << s.c << '\n'; break;
            +        case S::INT: std::cout << s.i << '\n'; break;
            +        case S::DOUBLE: std::cout << s.d << '\n'; break;
            +    }
            +}
            +
            +int main()
            +{
            +    S s = {S::CHAR, 'a'};
            +    print_s(s);
            +    s.tag = S::INT;
            +    s.i = 123;
            +    print_s(s);
            +}
            +
            +
            +

            (Download the source code for this example: tagged_union.cpp)

            +

            C++17 introduced a new feature called variant which generalizes this concept. +You can read more about it here.

            +

            Java has a more or less analogous feature called sealed classes +since version 17.

            +

            Enums in Rust

            +

            Let's see how they are defined in Rust.

            +
            #![allow(unused_assignments)]
            +#![allow(unused_variables)]
            +#![allow(dead_code)]
            +
            +#[derive(Debug)]
            +enum NamedSize {
            +    Small,
            +    Medium,
            +    Large,
            +    XL,
            +}
            +
            +#[derive(Debug)]
            +enum ShirtSize {
            +    Named(NamedSize),
            +    Numeric(u32),
            +}
            +
            +fn main() {
            +    println!(
            +        "Isn't it strange that some clothes' sizes are adjectives like {:?},",
            +        ShirtSize::Named(NamedSize::Small)
            +    );
            +    println!(
            +        "but sometimes they are numbers like {:?}?",
            +        ShirtSize::Numeric(42)
            +    );
            +}
            +
            +
            +

            (Download the source code for this example: enums.rs)

            +

            In Rust, enums are a core feature of the language. +You may have heard that one of Rust's defining characteristics is +the absence of "the billion dollar mistake". +So what can we do to say that a value is missing if there is no null?

            +

            In Rust, we can use the Option type to represent the absence of a value.

            +

            Option is defined as:

            +
            enum Option<T> {
            +    Some(T),
            +    None,
            +}
            +
            +

            The <T> part is called the "type parameter" and it causes Option to be generic. +We won't go deeper into this for now.

            +

            The fact that variables which could be null in other languages have a different type in Rust is +the solution to the billion dollar mistake!

            +
            #![allow(unused_assignments)]
            +#![allow(unused_variables)]
            +#![allow(dead_code)]
            +
            +fn main() {
            +    let mut not_null: i32 = 42;
            +    not_null = 43;
            +    // not_null = None; // this won't compile because it's a different type!
            +
            +    let mut nullable: Option<i32> = Some(42);
            +    nullable = None;
            +    nullable = Some(43);
            +
            +    // such construction is rare, but possible
            +    let mut double_nullable: Option<Option<i32>> = Some(Some(42));
            +    // assert_ne!(double_nullable, Some(42)); // this won't even compile because it's a different type!
            +    double_nullable = None;
            +    double_nullable = Some(None);
            +
            +    // None and Some(None) are different!
            +    assert_ne!(double_nullable, None);
            +
            +    // Now recall that division by 0 *panics*
            +    // A panic is an unrecoverable error
            +    // It is not an exception!
            +    // And in Rust there are no exceptions, so there are no try/catch blocks
            +    // Now let's imagine that we want to divide one number by another
            +    fn divide(dividend: i32, divisor: i32) -> i32 {
            +        dividend / divisor
            +    }
            +
            +    // We get the divisor from the user, so it can be 0
            +    // We want to handle this situation gracefully - we don't want to crash the program!
            +    // We can do this by using the Option<T> type
            +    fn safe_divide(dividend: i32, divisor: i32) -> Option<i32> {
            +        if divisor == 0 {
            +            None
            +        } else {
            +            Some(dividend / divisor)
            +        }
            +    }
            +
            +    // Fortunately, such a function is already included in the standard library
            +    let number: i32 = 42;
            +    // We need to specify the type explicitly
            +    // because checked_div is implemented for all integer types
            +    // and Rust won't know which type we want to use
            +    assert_eq!(number.checked_div(2), Some(21));
            +    assert_eq!(number.checked_div(0), None);
            +
            +    // Now let's imagine we search for a value in an array.
            +    let numbers = [1, 2, 3, 4, 5];
            +    let three = numbers.iter().copied().find(|&x| x == 3);
            +    assert_eq!(three, Some(3));
            +    let seven = numbers.iter().copied().find(|&x| x == 7);
            +    assert_eq!(seven, None);
            +    // We won't delve deeper into the details of how iterators work for now,
            +    // but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust
            +
            +    // Usually there are two kinds of methods:
            +    // ones that will panic if the argument is incorrect,
            +    // numbers[8]; // this will panic!
            +    // and `checked` ones that return an Option
            +    assert_eq!(numbers.get(8), None);
            +
            +    // We can use `unwrap` to get the value out of an Option
            +    // but we must be absolutely sure that the Option is Some, otherwise we'll get a panic
            +    // numbers.get(8).unwrap(); // this will panic!
            +    assert_eq!(numbers.get(8).copied().unwrap_or(0), 0); // or we can provide a default value
            +
            +    // Usually instead of unwrapping we use pattern matching, we'll get to this in a minute
            +    // but first let's see what else we can do with an option
            +    let number: Option<i32> = Some(42);
            +    // We can use `map` to transform the value inside an Option
            +    let doubled = number.map(|x| x * 2);
            +    assert_eq!(doubled, Some(84));
            +    // We can use flatten to reduce one level of nesting
            +    let nested = Some(Some(42));
            +    assert_eq!(nested.flatten(), Some(42));
            +    // We can use `and_then` to chain multiple options
            +    // This operation is called `flatmap` in some languages
            +    let chained = number
            +        .and_then(|x| x.checked_div(0))
            +        .and_then(|x| x.checked_div(2));
            +    assert_eq!(chained, None);
            +
            +    // The last two things we'll cover here are `take` and `replace`
            +    // They are important when dealing with non-Copy types
            +    // `take` will return the value inside an Option and leave a None in its place
            +    let mut option: Option<i32> = None;
            +    // Again, we need to specify the type
            +    // Even though we want to say that there is no value inside the Option,
            +    // this absent value must have a concrete type!
            +    assert_eq!(option.take(), None);
            +    assert_eq!(option, None);
            +
            +    let mut x = Some(2);
            +    let y = x.take();
            +    assert_eq!(x, None);
            +    assert_eq!(y, Some(2));
            +
            +    // `replace` can be used to swap the value inside an Option
            +    let mut x = Some(2);
            +    let old = x.replace(5);
            +    assert_eq!(x, Some(5));
            +    assert_eq!(old, Some(2));
            +
            +    let mut x = None;
            +    let old = x.replace(3);
            +    assert_eq!(x, Some(3));
            +    assert_eq!(old, None);
            +}
            +
            +
            +

            (Download the source code for this example: option.rs)

            +

            Pattern matching

            +

            Pattern matching is a powerful feature of Rust and many functional languages, but it's slowly making +its way into imperative languages like Java and Python as well.

            +
            #![allow(dead_code)]
            +#![allow(unused_variables)]
            +
            +fn main() {
            +    // Pattern matching is basically a switch on steroids.
            +    let number = rand::random::<i32>();
            +    match number % 7 {
            +        0 => println!("{number} is divisible by 7"),
            +        1 => println!("{number} is *almost* divisible by 7"),
            +        _ => println!("{number} is not divisible by 7"),
            +    }
            +
            +    #[derive(Debug)]
            +    enum Color {
            +        Pink,
            +        Brown,
            +        Lime,
            +    }
            +
            +    let color = Color::Lime;
            +    match color {
            +        Color::Pink => println!("My favorite color!"),
            +        _ => println!("Not my favorite color!"), // _ is a wildcard
            +                                                 // Rust will statically check that we covered all cases or included a default case.
            +    }
            +
            +    // We can also use pattern matching to match on multiple values.
            +    match (color, number % 7) {
            +        (Color::Pink, 0) => println!("My favorite color and number!"),
            +        (Color::Pink, _) => println!("My favorite color!"),
            +        (_, 0) => println!("My favorite number!"),
            +        (_, _) => println!("Not my favorite color or number!"),
            +    }
            +    // (This is not special syntax, we're just pattern matching tuples.)
            +
            +    // But we can also *destructure* the value
            +    struct Human {
            +        age: u8,
            +        favorite_color: Color,
            +    }
            +
            +    let john = Human {
            +        age: 42,
            +        favorite_color: Color::Pink,
            +    };
            +
            +    match &john {
            +        Human {
            +            age: 42,
            +            favorite_color: Color::Pink,
            +        } => println!("Okay, that's John!"),
            +        Human {
            +            favorite_color: Color::Pink,
            +            ..
            +        } => println!("Not John, but still his favorite color!"),
            +        _ => println!("Somebody else?"),
            +    }
            +
            +    // Note two things:
            +    // 1. Color is *not* Eq, so we can't use == to compare it, but pattern matching is fine.
            +    // 2. We *borrowed* the value, so we can use it after the match.
            +
            +    println!("John is {} years old and still kicking!", john.age);
            +
            +    // To save some time, we can use `if let` to match against only one thing
            +    // We could also use `while let ... {}` in the same way
            +    if let Color::Pink = &john.favorite_color {
            +        println!("He's also a man of great taste");
            +    }
            +
            +    // We can match ranges...
            +    match john.age {
            +        0..=12 => println!("John is a kid!"),
            +        13..=19 => println!("John is a teenager!"),
            +        20..=29 => println!("John is a young adult!"),
            +        30..=49 => println!("John is an adult!"),
            +        50..=69 => println!("John is mature!"),
            +        _ => println!("John is old!"),
            +    }
            +
            +    // We can use match and capture the value at the same time.
            +    match john.age {
            +        age @ 0..=12 => println!("John is a kid, age {}", age),
            +        age @ 13..=19 => println!("John is a teenager, age {}", age),
            +        age @ 20..=29 => println!("John is a young adult, age {}", age),
            +        age @ 30..=49 => println!("John is an adult, age {}", age),
            +        age @ 50..=69 => println!("John is mature, age {}", age),
            +        age => println!("John is old, age {}", age),
            +    }
            +
            +    // We can use guards to check for multiple conditions.
            +    match john.age {
            +        age @ 12..=19 if age % 2 == 1 => println!("John is an *odd* teenager, age {}", age),
            +        age if age % 2 == 0 => println!("John is an *even* man, age {}", age),
            +        _ => println!("John is normal"),
            +    }
            +
            +    // Finally, let's look at some references now
            +    let reference: &i32 = &4;
            +
            +    match reference {
            +        &val => println!("Value under reference is: {}", val),
            +    }
            +
            +    // `ref` can be used to create a reference when destructuring
            +    let Human {
            +        age,
            +        ref favorite_color,
            +    } = john;
            +    // `john` is still valid, because we borrowed using `ref`
            +    if let Color::Pink = &john.favorite_color {
            +        println!("John still has his color - {:?}!", favorite_color);
            +    }
            +
            +    let mut john = john;
            +
            +    // `ref mut` borrows mutably
            +    let Human {
            +        age,
            +        ref mut favorite_color,
            +    } = john;
            +    // We use `*` to dereference
            +    *favorite_color = Color::Brown;
            +    println!(
            +        "Tastes do change with time and John likes {:?} now.",
            +        john.favorite_color
            +    );
            +}
            +
            +
            +

            (Download the source code for this example: pattern_matching.rs)

            +

            Result

            +

            We said there are no exceptions in Rust and panics mean errors which cannot be caught. +So how do we handle situations which can fail? That's where the Result type comes in.

            +
            #![allow(dead_code)]
            +#![allow(unused_variables)]
            +
            +use std::fs::File;
            +use std::io;
            +use std::io::Read;
            +
            +// Let's try reading from a file.
            +// Obviously this can fail.
            +fn first_try() -> io::Result<String> {
            +    let file = File::open("/dev/random");
            +    match file {
            +        Ok(mut file) => {
            +            // We got a file!
            +            let mut buffer = vec![0; 128];
            +            // Matching each result quickly become tedious...
            +            match file.read_exact(&mut buffer) {
            +                Ok(_) => {
            +                    let gibberish = String::from_utf8_lossy(&buffer);
            +                    Ok(gibberish.to_string())
            +                }
            +                Err(error) => Err(error),
            +            }
            +        }
            +        Err(error) => {
            +            Err(error) // This is needed in order to change the type from `io::Result<File>` to `io::Result<()>`
            +        }
            +    }
            +}
            +
            +// The '?' operator allows us to return early in case of an error
            +// (it automatically converts the error type)
            +fn second_try(filename: &'static str) -> io::Result<String> {
            +    let mut file = File::open(filename)?;
            +    let mut buffer = vec![0; 128];
            +    file.read_exact(&mut buffer)?;
            +    let gibberish = String::from_utf8_lossy(&buffer);
            +    Ok(gibberish.to_string())
            +}
            +
            +fn main() {
            +    let filenames = [
            +        "/dev/random",
            +        "/dev/null",
            +        "/dev/cpu",
            +        "/dev/fuse",
            +        "there_certainly_is_no_such_file",
            +    ];
            +    for filename in filenames {
            +        println!("Trying to read from '{}'", filename);
            +        match second_try(filename) {
            +            Ok(gibberish) => println!("{}", gibberish),
            +            Err(error) => println!("Error: {}", error),
            +        }
            +    }
            +}
            +
            +
            +

            (Download the source code for this example: result.rs)

            +

            Obligatory reading

            + +

            Assignment 2 (graded)

            +

            Communications

            +

            Deadline: 23.10.2024 23:59

            + + +
            +
            + + + + +
            + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/03-data-types/module_system/module_system.html b/lessons/03-data-types/module_system/module_system.html new file mode 100644 index 0000000..104212c --- /dev/null +++ b/lessons/03-data-types/module_system/module_system.html @@ -0,0 +1,253 @@ +
            +

            Module system

            +

            Managing code structure in a growing project.
            +Testing and sharing code conveniently.

            +
            +
            +

            Module system consists of:

            +
              +
            • Packages: A Cargo feature that lets you build, test, and share crates
            • +
            • Crates: A tree of modules that produces a library or executable
            • +
            • Modules and use: Let you control the organization, scope, and privacy of paths
            • +
            • Paths: A way of naming an item, such as a struct, function, or module
            • +
            +
            +
            +

            Package structure

            +
            my-project
            +├── Cargo.lock             <-- actual dependencies' versions
            +├── Cargo.toml             <-- package configuration, dependency version requirements
            +└── src
            +    ├── configuration
            +    │   ├── run.rs
            +    │   └── mod.rs
            +    ├── lib.rs             <-- root of the lib crate
            +    ├── bin1
            +    │   ├── distribution.rs
            +    │   └── main.rs        <-- root of bin crate `bin1`
            +    └── bin2.rs            <-- root of bin crate `bin2`
            +
            +
            +
            +

            Lib crates can be shared

            +
              +
            • crates.io is the main crate repository.
            • +
            • If you specify a dependency in Cargo.toml, it's fetched from crates.io automatically by Cargo.
            • +
            • lib.rs is the root of a lib crate.
            • +
            +
            +
            +

            Binary crates can be executed

            +
              +
            • cargo run executes the bin crate in your package.
            • +
            • If you have multiple bin crates, you have to specify which to run:
              +cargo run --bin <bin_name>
            • +
            • Each bin crate in a package can import code from the lib crate there.
            • +
            +
            +
            + +
            mod front_of_house {
            +    mod hosting {
            +        fn add_to_waitlist() {}
            +        fn seat_at_table() {}
            +    }
            +
            +    // Alternatively, this could be located in `serving.rs` file and imported.
            +    mod serving {
            +        fn take_order() {}
            +        fn serve_order() {}
            +        fn take_payment() {}
            +    }
            +}
            +
            +
            +
            + +
            crate
            + └── front_of_house
            +     ├── hosting
            +     │   ├── add_to_waitlist
            +     │   └── seat_at_table
            +     └── serving
            +         ├── take_order
            +         ├── serve_order
            +         └── take_payment
            +
            +
            +
            +

            Exports & imports

            +
              +
            • exports: using privacy modifier (pub, pub(crate), [no modifier])
            • +
            +
            mod some_mod {
            +    struct ModulePublic;
            +    pub(super) struct ParentModulePublic;
            +    pub(crate) struct CratePublic;
            +    pub struct WorldPublic;
            +}
            +
            +
              +
            • imports: using use statement
            • +
            +
            use some_mod::CratePublic;
            +pub use some_mod::WorldPublic; // <-- re-export
            +
            +
            +
            \ No newline at end of file diff --git a/lessons/03-data-types/module_system/module_system.pdf b/lessons/03-data-types/module_system/module_system.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e58da8877c276ce9f237bd94e1137190d06f4724 GIT binary patch literal 43577 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 ={{t0jX(`klV7Y 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 = Some(42); + nullable = None; + nullable = Some(43); + + // such construction is rare, but possible + let mut double_nullable: Option> = Some(Some(42)); + // assert_ne!(double_nullable, Some(42)); // this won't even compile because it's a different type! + double_nullable = None; + double_nullable = Some(None); + + // None and Some(None) are different! + assert_ne!(double_nullable, None); + + // Now recall that division by 0 *panics* + // A panic is an unrecoverable error + // It is not an exception! + // And in Rust there are no exceptions, so there are no try/catch blocks + // Now let's imagine that we want to divide one number by another + fn divide(dividend: i32, divisor: i32) -> i32 { + dividend / divisor + } + + // We get the divisor from the user, so it can be 0 + // We want to handle this situation gracefully - we don't want to crash the program! + // We can do this by using the Option type + fn safe_divide(dividend: i32, divisor: i32) -> Option { + if divisor == 0 { + None + } else { + Some(dividend / divisor) + } + } + + // Fortunately, such a function is already included in the standard library + let number: i32 = 42; + // We need to specify the type explicitly + // because checked_div is implemented for all integer types + // and Rust won't know which type we want to use + assert_eq!(number.checked_div(2), Some(21)); + assert_eq!(number.checked_div(0), None); + + // Now let's imagine we search for a value in an array. + let numbers = [1, 2, 3, 4, 5]; + let three = numbers.iter().copied().find(|&x| x == 3); + assert_eq!(three, Some(3)); + let seven = numbers.iter().copied().find(|&x| x == 7); + assert_eq!(seven, None); + // We won't delve deeper into the details of how iterators work for now, + // but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust + + // Usually there are two kinds of methods: + // ones that will panic if the argument is incorrect, + // numbers[8]; // this will panic! + // and `checked` ones that return an Option + assert_eq!(numbers.get(8), None); + + // We can use `unwrap` to get the value out of an Option + // but we must be absolutely sure that the Option is Some, otherwise we'll get a panic + // numbers.get(8).unwrap(); // this will panic! + assert_eq!(numbers.get(8).copied().unwrap_or(0), 0); // or we can provide a default value + + // Usually instead of unwrapping we use pattern matching, we'll get to this in a minute + // but first let's see what else we can do with an option + let number: Option = Some(42); + // We can use `map` to transform the value inside an Option + let doubled = number.map(|x| x * 2); + assert_eq!(doubled, Some(84)); + // We can use flatten to reduce one level of nesting + let nested = Some(Some(42)); + assert_eq!(nested.flatten(), Some(42)); + // We can use `and_then` to chain multiple options + // This operation is called `flatmap` in some languages + let chained = number + .and_then(|x| x.checked_div(0)) + .and_then(|x| x.checked_div(2)); + assert_eq!(chained, None); + + // The last two things we'll cover here are `take` and `replace` + // They are important when dealing with non-Copy types + // `take` will return the value inside an Option and leave a None in its place + let mut option: Option = None; + // Again, we need to specify the type + // Even though we want to say that there is no value inside the Option, + // this absent value must have a concrete type! + assert_eq!(option.take(), None); + assert_eq!(option, None); + + let mut x = Some(2); + let y = x.take(); + assert_eq!(x, None); + assert_eq!(y, Some(2)); + + // `replace` can be used to swap the value inside an Option + let mut x = Some(2); + let old = x.replace(5); + assert_eq!(x, Some(5)); + assert_eq!(old, Some(2)); + + let mut x = None; + let old = x.replace(3); + assert_eq!(x, Some(3)); + assert_eq!(old, None); +} diff --git a/lessons/03-data-types/pattern_matching.rs b/lessons/03-data-types/pattern_matching.rs new file mode 100644 index 0000000..215a74a --- /dev/null +++ b/lessons/03-data-types/pattern_matching.rs @@ -0,0 +1,128 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +fn main() { + // Pattern matching is basically a switch on steroids. + let number = rand::random::(); + match number % 7 { + 0 => println!("{number} is divisible by 7"), + 1 => println!("{number} is *almost* divisible by 7"), + _ => println!("{number} is not divisible by 7"), + } + + #[derive(Debug)] + enum Color { + Pink, + Brown, + Lime, + } + + let color = Color::Lime; + match color { + Color::Pink => println!("My favorite color!"), + _ => println!("Not my favorite color!"), // _ is a wildcard + // Rust will statically check that we covered all cases or included a default case. + } + + // We can also use pattern matching to match on multiple values. + match (color, number % 7) { + (Color::Pink, 0) => println!("My favorite color and number!"), + (Color::Pink, _) => println!("My favorite color!"), + (_, 0) => println!("My favorite number!"), + (_, _) => println!("Not my favorite color or number!"), + } + // (This is not special syntax, we're just pattern matching tuples.) + + // But we can also *destructure* the value + struct Human { + age: u8, + favorite_color: Color, + } + + let john = Human { + age: 42, + favorite_color: Color::Pink, + }; + + match &john { + Human { + age: 42, + favorite_color: Color::Pink, + } => println!("Okay, that's John!"), + Human { + favorite_color: Color::Pink, + .. + } => println!("Not John, but still his favorite color!"), + _ => println!("Somebody else?"), + } + + // Note two things: + // 1. Color is *not* Eq, so we can't use == to compare it, but pattern matching is fine. + // 2. We *borrowed* the value, so we can use it after the match. + + println!("John is {} years old and still kicking!", john.age); + + // To save some time, we can use `if let` to match against only one thing + // We could also use `while let ... {}` in the same way + if let Color::Pink = &john.favorite_color { + println!("He's also a man of great taste"); + } + + // We can match ranges... + match john.age { + 0..=12 => println!("John is a kid!"), + 13..=19 => println!("John is a teenager!"), + 20..=29 => println!("John is a young adult!"), + 30..=49 => println!("John is an adult!"), + 50..=69 => println!("John is mature!"), + _ => println!("John is old!"), + } + + // We can use match and capture the value at the same time. + match john.age { + age @ 0..=12 => println!("John is a kid, age {}", age), + age @ 13..=19 => println!("John is a teenager, age {}", age), + age @ 20..=29 => println!("John is a young adult, age {}", age), + age @ 30..=49 => println!("John is an adult, age {}", age), + age @ 50..=69 => println!("John is mature, age {}", age), + age => println!("John is old, age {}", age), + } + + // We can use guards to check for multiple conditions. + match john.age { + age @ 12..=19 if age % 2 == 1 => println!("John is an *odd* teenager, age {}", age), + age if age % 2 == 0 => println!("John is an *even* man, age {}", age), + _ => println!("John is normal"), + } + + // Finally, let's look at some references now + let reference: &i32 = &4; + + match reference { + &val => println!("Value under reference is: {}", val), + } + + // `ref` can be used to create a reference when destructuring + let Human { + age, + ref favorite_color, + } = john; + // `john` is still valid, because we borrowed using `ref` + if let Color::Pink = &john.favorite_color { + println!("John still has his color - {:?}!", favorite_color); + } + + let mut john = john; + + // `ref mut` borrows mutably + let Human { + age, + ref mut favorite_color, + } = john; + // We use `*` to dereference + *favorite_color = Color::Brown; + println!( + "Tastes do change with time and John likes {:?} now.", + john.favorite_color + ); +} diff --git a/lessons/03-data-types/result.rs b/lessons/03-data-types/result.rs new file mode 100644 index 0000000..ffd0797 --- /dev/null +++ b/lessons/03-data-types/result.rs @@ -0,0 +1,56 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +use std::fs::File; +use std::io; +use std::io::Read; + +// Let's try reading from a file. +// Obviously this can fail. +fn first_try() -> io::Result { + let file = File::open("/dev/random"); + match file { + Ok(mut file) => { + // We got a file! + let mut buffer = vec![0; 128]; + // Matching each result quickly become tedious... + match file.read_exact(&mut buffer) { + Ok(_) => { + let gibberish = String::from_utf8_lossy(&buffer); + Ok(gibberish.to_string()) + } + Err(error) => Err(error), + } + } + Err(error) => { + Err(error) // This is needed in order to change the type from `io::Result` to `io::Result<()>` + } + } +} + +// The '?' operator allows us to return early in case of an error +// (it automatically converts the error type) +fn second_try(filename: &'static str) -> io::Result { + let mut file = File::open(filename)?; + let mut buffer = vec![0; 128]; + file.read_exact(&mut buffer)?; + let gibberish = String::from_utf8_lossy(&buffer); + Ok(gibberish.to_string()) +} + +fn main() { + let filenames = [ + "/dev/random", + "/dev/null", + "/dev/cpu", + "/dev/fuse", + "there_certainly_is_no_such_file", + ]; + for filename in filenames { + println!("Trying to read from '{}'", filename); + match second_try(filename) { + Ok(gibberish) => println!("{}", gibberish), + Err(error) => println!("Error: {}", error), + } + } +} diff --git a/lessons/03-data-types/tagged_union.cpp b/lessons/03-data-types/tagged_union.cpp new file mode 100644 index 0000000..ae07b6e --- /dev/null +++ b/lessons/03-data-types/tagged_union.cpp @@ -0,0 +1,35 @@ +#include + +// Taken from: https://en.cppreference.com/w/cpp/language/union + +// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), +// and three variant members (c, i, d) +struct S +{ + enum{CHAR, INT, DOUBLE} tag; + union + { + char c; + int i; + double d; + }; +}; + +void print_s(const S& s) +{ + switch(s.tag) + { + case S::CHAR: std::cout << s.c << '\n'; break; + case S::INT: std::cout << s.i << '\n'; break; + case S::DOUBLE: std::cout << s.d << '\n'; break; + } +} + +int main() +{ + S s = {S::CHAR, 'a'}; + print_s(s); + s.tag = S::INT; + s.i = 123; + print_s(s); +} diff --git a/lessons/03_data_types/module_system/module-system/index.html b/lessons/03_data_types/module_system/module-system/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/03_data_types/module_system/module-system/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
            +

            Welcome to Zola!

            +

            + You're seeing this page because we couldn't find a template to render. +

            +

            + To modify this page, create a page.html file in the templates directory or + install a theme. +
            + You can find what variables are available in this template in the documentation. +

            +
            + + + + diff --git a/lessons/04-feedback-1/index.html b/lessons/04-feedback-1/index.html new file mode 100644 index 0000000..4f7b607 --- /dev/null +++ b/lessons/04-feedback-1/index.html @@ -0,0 +1,301 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
            + + +
            + +
            + +
            +
            +
              +
              +
              + +
              + +

              Feedback #1

              +

              + 2022-10-31 (last edit: 2022-10-31) +

              +

              Feedback

              +

              Unwrapping

              +

              Instead of this:

              +
              if self.favorite_color.is_some() {
              +    self.favorite_color.as_mut().unwrap().lighten();
              +}
              +
              +

              do this:

              +
              if let Some(ref mut color) = self.favorite_color {
              +    color.lighten();
              +}
              +
              +

              or

              +
              if let Some(color) = &mut self.favorite_color {
              +    color.lighten();
              +}
              +
              +

              (unwrapping is a code smell)

              +

              Spot the overflow

              +
              Color::Rgb(r, g, b) => *b > (*r + *g) / 2,
              +
              +

              1/3

              +
              Color::Rgb(r, g, b) => (*b as u16) * 3 > (*r as u16) + (*g as u16) + (*b as u16),
              +
              +

              No need to cast to u16. If b accounts for 1/3 of the sum, it's enough to check that it's bigger than both r and g.

              +

              Format

              +
              Color::Named(ref mut name) => *name = "light ".to_string() + name,
              +
              +

              There's a format! macro for this.

              +
              Color::Named(ref mut name) => *name = format!("light {name}"),
              +
              +

              From vs Into vs as

              +
              let tmp1: u32 = <u8 as Into<u32>>::into(*c) * 2;
              +
              +

              This could be written as

              +
              let tmp1: u32 = (*c).into() * 2;
              +
              +

              or even simpler (note the omission of the type annotation):

              +
              let tmp1 = u32::from(*c) * 2;
              +
              +

              However in most cases of numeric conversion you can just use as:

              +
              let tmp1 = *c as u32 * 2;
              +
              +

              Into trait docs

              +

              Saturating addition

              +

              There's a saturating_add method on u8 which does exactly what we wanted. +But it was fun watching you struggle with it :)

              +
              fn lighten(&mut self) {
              +    match self {
              +        Color::Named(name) => *name = "light ".to_string() + name,
              +        Color::Rgb(r, g, b) => {
              +            *r = r.saturating_add(10);
              +            *g = g.saturating_add(10);
              +            *b = b.saturating_add(10);
              +        }
              +    }
              +}
              +
              +

              Exchange

              +
              fn exchange_items(robot1: &mut Robot, robot2: &mut Robot) {
              +    mem::swap(&mut robot1.held_item, &mut robot2.held_item);
              +}
              +
              +

              Swap is the preferred way to exchange the contents of two variables.

              +

              Regex? Nope

              +

              There's no need to use a regex here. String has a contains method.

              +

              If you really want to use a regex, +you can use the lazy_static crate to avoid recompiling the regex every time you call the function.

              + + +
              +
              + + + + +
              + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/05-types-reasoning/basic_trait.rs b/lessons/05-types-reasoning/basic_trait.rs new file mode 100644 index 0000000..1c76202 --- /dev/null +++ b/lessons/05-types-reasoning/basic_trait.rs @@ -0,0 +1,38 @@ +#![allow(dead_code)] + +trait Summary { + fn summarize(&self) -> String; +} + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Summary for NewsArticle { + fn summarize(&self) -> String { + format!("{}, by {} ({})", self.headline, self.author, self.location) + } +} + +struct Tweet { + username: String, + content: String, +} + +impl Summary for Tweet { + fn summarize(&self) -> String { + format!("{}: {}", self.username, self.content) + } +} + +fn main() { + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + println!("1 new tweet: {}", tweet.summarize()); +} diff --git a/lessons/05-types-reasoning/basic_trait_display.rs b/lessons/05-types-reasoning/basic_trait_display.rs new file mode 100644 index 0000000..07cf611 --- /dev/null +++ b/lessons/05-types-reasoning/basic_trait_display.rs @@ -0,0 +1,40 @@ +#![allow(dead_code)] + +use std::fmt::Display; + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Display for NewsArticle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}, by {} ({})", + self.headline, self.author, self.location + ) + } +} + +struct Tweet { + username: String, + content: String, +} + +impl Display for Tweet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {}", self.username, self.content) + } +} + +fn main() { + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + println!("1 new tweet: {}", tweet); +} diff --git a/lessons/05-types-reasoning/generic_largest.rs b/lessons/05-types-reasoning/generic_largest.rs new file mode 100644 index 0000000..7aa6a3b --- /dev/null +++ b/lessons/05-types-reasoning/generic_largest.rs @@ -0,0 +1,23 @@ +fn largest(list: &[T]) -> T { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest(&char_list); + println!("The largest char is {}", result); +} diff --git a/lessons/05-types-reasoning/generics.rs b/lessons/05-types-reasoning/generics.rs new file mode 100644 index 0000000..837f52f --- /dev/null +++ b/lessons/05-types-reasoning/generics.rs @@ -0,0 +1,89 @@ +#![allow(dead_code)] + +use std::fmt::Debug; + +// generic enums +enum OurOption { + Some(T), + None, +} + +// generic structs +struct Tuple2 { + x: T, + y: U, +} + +// generic implementation +impl Tuple2 { + fn new(x: T, y: U) -> Self { + Self { x, y } + } +} + +struct Pair { + x: T, + y: T, +} + +// conditional implementation +impl Pair { + fn largest(&self) -> T { + if self.x > self.y { + self.x + } else { + self.y + } + } +} + +// alternative syntax +impl Pair +where + T: PartialOrd + Copy, +{ + fn smallest(&self) -> T { + if self.x < self.y { + self.x + } else { + self.y + } + } +} + +// Here information about the concrete underlying type is preserved. +fn cloning_machine(item: &T) -> T { + item.clone() +} + +// Here information about the concrete underlying type is erased. +// We can only either format or clone the result. +fn erasing_cloning_machine1(item: &(impl Clone + Debug)) -> impl Clone + Debug { + item.clone() +} + +// Ditto. +fn erasing_cloning_machine2(item: &T) -> impl Clone + Debug { + item.clone() +} + +fn main() { + let _opt = OurOption::Some(10); + + let _p1 = Tuple2 { x: 5, y: 10 }; + let _p2 = Tuple2::new(1, 2.5); + + let arr = [1, 2, 3]; + + let arr2 = cloning_machine(&arr); + let _x = arr2[0]; // This compiles, because `cloning_machine` preserves the type. + println!("{:?}", arr2); + + let arr3 = erasing_cloning_machine1(&arr); + // arr3[0]; // won't compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` + println!("{:?}", arr3); + + let arr4 = erasing_cloning_machine2(&arr); + // arr4[0]; // won't compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` + println!("{:?}", arr4); +} diff --git a/lessons/05-types-reasoning/generics_fun.rs b/lessons/05-types-reasoning/generics_fun.rs new file mode 100644 index 0000000..241c389 --- /dev/null +++ b/lessons/05-types-reasoning/generics_fun.rs @@ -0,0 +1,35 @@ +use std::fmt::{Display, Formatter}; + +trait DefaultishablyPrintable { + fn defaultish_print() + where + T: Display + Default, + { + println!("{}", T::default()) + } +} + +struct Foo; + +struct Bar; + +impl Display for Bar { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("this is a bar") + } +} + +impl Default for Bar { + fn default() -> Self { + Bar // well, we have no other choice + } +} + +impl DefaultishablyPrintable for Foo {} + +impl DefaultishablyPrintable for Foo {} + +fn main() { + >::defaultish_print(); + >::defaultish_print(); +} diff --git a/lessons/05-types-reasoning/impl_trait.rs b/lessons/05-types-reasoning/impl_trait.rs new file mode 100644 index 0000000..e42329f --- /dev/null +++ b/lessons/05-types-reasoning/impl_trait.rs @@ -0,0 +1,73 @@ +#![allow(dead_code)] + +use std::fmt::Display; + +trait Summary { + fn summarize(&self) -> impl Display; +} + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Display for NewsArticle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "{}, by {} ({})", + self.headline, self.author, self.location + )?; + f.write_str(&self.content) + } +} + +struct NewsArticleSummarizer<'a>(&'a NewsArticle); + +impl Display for NewsArticleSummarizer<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let article = self.0; + write!( + f, + "{}, by {} ({})", + article.headline, article.author, article.location + ) + } +} + +impl Summary for NewsArticle { + fn summarize(&self) -> impl Display { + NewsArticleSummarizer(self) + } +} + +struct Tweet { + username: String, + content: String, +} + +impl Summary for Tweet { + fn summarize(&self) -> impl Display { + struct TweetSummarizer<'a>(&'a Tweet); + + impl Display for TweetSummarizer<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let tweet = self.0; + write!(f, "{}: {}", tweet.username, tweet.content) + } + } + + TweetSummarizer(self) + } +} + +fn main() { + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + println!("1 new tweet: {}", tweet.summarize()); +} diff --git a/lessons/05-types-reasoning/index.html b/lessons/05-types-reasoning/index.html new file mode 100644 index 0000000..b65bd1f --- /dev/null +++ b/lessons/05-types-reasoning/index.html @@ -0,0 +1,1194 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
              + + +
              + +
              + +
              +
              +
                +
                +
                + +
                + +

                Reasoning About Types

                +

                + 2024-10-24 (last edit: 2024-10-24) +

                +

                Type traits

                +

                Traits are a way to defined common behavior between different types. They can be compared to interfaces from many other mainstream languages or to type classes from Haskell, however, Rust is not an object-oriented language and there are some notable differences between type traits and Java interfaces.

                +

                The way we describe behavior in Rust is through methods. Traits consist of a set of these methods which then should be implemented by a type. We've already encountered examples of these, like the Clone trait which specified that the clone() method can be called on some given type. Now, let's take a deeper look and try defining our own trait.

                +
                #![allow(dead_code)]
                +
                +trait Summary {
                +    fn summarize(&self) -> String;
                +}
                +
                +struct NewsArticle {
                +    headline: String,
                +    location: String,
                +    author: String,
                +    content: String,
                +}
                +
                +impl Summary for NewsArticle {
                +    fn summarize(&self) -> String {
                +        format!("{}, by {} ({})", self.headline, self.author, self.location)
                +    }
                +}
                +
                +struct Tweet {
                +    username: String,
                +    content: String,
                +}
                +
                +impl Summary for Tweet {
                +    fn summarize(&self) -> String {
                +        format!("{}: {}", self.username, self.content)
                +    }
                +}
                +
                +fn main() {
                +    let tweet = Tweet {
                +        username: String::from("horse_ebooks"),
                +        content: String::from("of course, as you probably already know, people"),
                +    };
                +
                +    println!("1 new tweet: {}", tweet.summarize());
                +}
                +
                +
                +

                (Download the source code for this example: basic_trait.rs)

                +

                Default implementations

                +

                Trait definitions can also be provided with default implementations of behaviors.

                +
                #![allow(dead_code)]
                +
                +struct Upload {
                +    filename: String,
                +}
                +
                +#[allow(dead_code)]
                +struct Photo {
                +    filename: String,
                +    width: u32,
                +    height: u32,
                +}
                +
                +trait Description {
                +    fn describe(&self) -> String {
                +        String::from("No description available.")
                +    }
                +}
                +
                +// All default implementations
                +impl Description for Upload {}
                +
                +// Default implementations can be overwritten
                +impl Description for Photo {
                +    fn describe(&self) -> String {
                +        format!("{} ({} x {})", self.filename, self.width, self.height)
                +    }
                +}
                +
                +// Default implementations can rely on methods with no defaults
                +trait Size {
                +    fn width(&self) -> u32;
                +    fn height(&self) -> u32;
                +
                +    fn size(&self) -> u32 {
                +        self.width() * self.height()
                +    }
                +}
                +
                +impl Size for Photo {
                +    fn width(&self) -> u32 {
                +        self.width
                +    }
                +
                +    fn height(&self) -> u32 {
                +        self.height
                +    }
                +
                +    // Using default impl of `size()`
                +}
                +
                +fn main() {
                +    let upload = Upload {
                +        filename: String::from("notes.txt"),
                +    };
                +
                +    println!("Upload: {}", upload.describe());
                +
                +    let photo = Photo {
                +        filename: String::from("stock_crustacean.png"),
                +        width: 100,
                +        height: 150,
                +    };
                +
                +    println!("Photo: {}", photo.describe());
                +    println!("Size: {}", photo.size());
                +}
                +
                +
                +

                (Download the source code for this example: trait_default.rs)

                +

                What about derive?

                +

                There is a trait-related thing we have used quite extensively and not explained yet, namely the #[derive] attribute. What it does is generate items (in our case a trait implementation) based on the given data definition (here a struct). Below you can find a list of derivable traits from the standard library. Writing derivation rules for user defined traits is also possible, but goes out of the scope of this lesson.

                +

                Derivable traits:

                +
                  +
                • +

                  Equality traits: Eq, PartialEq and comparison traits: Ord and PartialOrd. The Partial- versions exist because there are types which don't fulfill the reflexivity requirement of equality (NaN != NaN) or do not form a total order ( NaN < 0.0 == false and NaN >= 0.0 == false).

                  +
                • +
                • +

                  Data duplication traits: Clone and Copy

                  +
                • +
                • +

                  Hash - allows using values of that type as keys in a hashmap

                  +
                • +
                • +

                  Default - provides a zero-arg constructor function

                  +
                • +
                • +

                  Debug - provides a formatting of the value which can be used in debugging context. It should NOT be implemented manually. In general, if it's possible to derive the Debug, there are no reasons against doing it.

                  +
                • +
                +

                When is it possible to derive a trait?

                +

                When all fields of a struct/variants of an enum implement that trait.

                +

                Should all traits always be derived if it is possible?

                +

                No. Although it may be tempting to just slap #[derive(Clone, Copy)] everywhere, it would be counter-effective. For example, at some later point you might add a non-Copy field to the struct and your (or, what's worse, someone else's!) code would break. Another example: it makes little sense to use containers as keys in hashmaps or to compare tweets.

                +

                Generics

                +

                Suppose we want to find the largest element in a sequence and return it. Very much on purpose, we didn't specify what type these elements would be - ideally, we would love it to work on all types that have a defined notion of a largest element. However, to make things simpler for now, let's focus only on two primitive types: i32 and char. Let's try to write the code:

                +
                fn largest_i32(list: &[i32]) -> i32 {
                +    let mut largest = list[0];
                +
                +    for &item in list {
                +        if item > largest {
                +            largest = item;
                +        }
                +    }
                +
                +    largest
                +}
                +
                +fn largest_char(list: &[char]) -> char {
                +    let mut largest = list[0];
                +
                +    for &item in list {
                +        if item > largest {
                +            largest = item;
                +        }
                +    }
                +
                +    largest
                +}
                +
                +fn main() {
                +    let number_list = vec![34, 50, 25, 100, 65];
                +
                +    let result = largest_i32(&number_list);
                +    println!("The largest number is {}", result);
                +
                +    let char_list = vec!['y', 'm', 'a', 'q'];
                +
                +    let result = largest_char(&char_list);
                +    println!("The largest char is {}", result);
                +}
                +
                +
                +

                (Download the source code for this example: non_generic.rs)

                +

                Perfect, it works! Now only twenty more types to go...

                +

                Fortunately, Rust gives us a way to avoid all this code duplication and generalize the types we're working on.

                +
                fn largest<T>(list: &[T]) -> T {
                +    let mut largest = list[0];
                +
                +    for &item in list {
                +        if item > largest {
                +            largest = item;
                +        }
                +    }
                +
                +    largest
                +}
                +
                +

                Cleaner already - we merged possibly very many implementations into one. But, when we try to compile this:

                +
                error[E0369]: binary operation `>` cannot be applied to type `T`
                + --> src/main.rs:5:17
                +  |
                +5 |         if item > largest {
                +  |            ---- ^ ------- T
                +  |            |
                +  |            T
                +  |
                +help: consider restricting type parameter `T`
                +  |
                +1 | fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> T {
                +  |             ++++++++++++++++++++++
                +
                +

                Since T can be of absolutely any type now, the compiler cannot be sure that operator > is defined. This aligns with what we wanted, as without comparing elements we don't have a notion of the largest one either. As always, the compiler comes to our aid:

                +
                fn largest<T: PartialOrd>(list: &[T]) -> T {
                +    let mut largest = list[0];
                +
                +    for &item in list {
                +        if item > largest {
                +            largest = item;
                +        }
                +    }
                +
                +    largest
                +}
                +
                +

                We call this a trait bound, a way to provide constraints on what kind of types we are talking about in a given context. This implementation almost works now. Let's look at the new error.

                +
                error[E0508]: cannot move out of type `[T]`, a non-copy slice
                + --> src/main.rs:2:23
                +  |
                +2 |     let mut largest = list[0];
                +  |                       ^^^^^^^
                +  |                       |
                +  |                       cannot move out of here
                +  |                       move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait
                +  |                       help: consider borrowing here: `&list[0]`
                +
                +error[E0507]: cannot move out of a shared reference
                + --> src/main.rs:4:18
                +  |
                +4 |     for &item in list {
                +  |         -----    ^^^^
                +  |         ||
                +  |         |data moved here
                +  |         |move occurs because `item` has type `T`, which does not implement the `Copy` trait
                +  |         help: consider removing the `&`: `item`
                +
                +

                Our function attempts to take ownership, but, again, the compiler doesn't know whether T can just be trivially copied. Rust allows us to combine multiple trait bounds together:

                +
                fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
                +    let mut largest = list[0];
                +
                +    for &item in list {
                +        if item > largest {
                +            largest = item;
                +        }
                +    }
                +
                +    largest
                +}
                +
                +fn main() {
                +    let number_list = vec![34, 50, 25, 100, 65];
                +
                +    let result = largest(&number_list);
                +    println!("The largest number is {}", result);
                +
                +    let char_list = vec!['y', 'm', 'a', 'q'];
                +
                +    let result = largest(&char_list);
                +    println!("The largest char is {}", result);
                +}
                +
                +
                +

                (Download the source code for this example: generic_largest.rs)

                +

                A powerful tool

                +

                There's a lot more that we can do with generics:

                +
                #![allow(dead_code)]
                +
                +use std::fmt::Debug;
                +
                +// generic enums
                +enum OurOption<T> {
                +    Some(T),
                +    None,
                +}
                +
                +// generic structs
                +struct Tuple2<T, U> {
                +    x: T,
                +    y: U,
                +}
                +
                +// generic implementation
                +impl<T, U> Tuple2<T, U> {
                +    fn new(x: T, y: U) -> Self {
                +        Self { x, y }
                +    }
                +}
                +
                +struct Pair<T> {
                +    x: T,
                +    y: T,
                +}
                +
                +// conditional implementation
                +impl<T: PartialOrd + Copy> Pair<T> {
                +    fn largest(&self) -> T {
                +        if self.x > self.y {
                +            self.x
                +        } else {
                +            self.y
                +        }
                +    }
                +}
                +
                +// alternative syntax
                +impl<T> Pair<T>
                +where
                +    T: PartialOrd + Copy,
                +{
                +    fn smallest(&self) -> T {
                +        if self.x < self.y {
                +            self.x
                +        } else {
                +            self.y
                +        }
                +    }
                +}
                +
                +// Here information about the concrete underlying type is preserved.
                +fn cloning_machine<T: Clone + Debug>(item: &T) -> T {
                +    item.clone()
                +}
                +
                +// Here information about the concrete underlying type is erased.
                +// We can only either format or clone the result.
                +fn erasing_cloning_machine1(item: &(impl Clone + Debug)) -> impl Clone + Debug {
                +    item.clone()
                +}
                +
                +// Ditto.
                +fn erasing_cloning_machine2<T: Clone + Debug>(item: &T) -> impl Clone + Debug {
                +    item.clone()
                +}
                +
                +fn main() {
                +    let _opt = OurOption::Some(10);
                +
                +    let _p1 = Tuple2 { x: 5, y: 10 };
                +    let _p2 = Tuple2::new(1, 2.5);
                +
                +    let arr = [1, 2, 3];
                +
                +    let arr2 = cloning_machine(&arr);
                +    let _x = arr2[0]; // This compiles, because `cloning_machine` preserves the type.
                +    println!("{:?}", arr2);
                +
                +    let arr3 = erasing_cloning_machine1(&arr);
                +    // arr3[0]; // won't compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug`
                +    println!("{:?}", arr3);
                +
                +    let arr4 = erasing_cloning_machine2(&arr);
                +    // arr4[0]; // won't compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug`
                +    println!("{:?}", arr4);
                +}
                +
                +
                +

                (Download the source code for this example: generics.rs)

                +

                A bit more involved example:

                +
                use std::fmt::{Display, Formatter};
                +
                +trait DefaultishablyPrintable<T> {
                +    fn defaultish_print()
                +    where
                +        T: Display + Default,
                +    {
                +        println!("{}", T::default())
                +    }
                +}
                +
                +struct Foo;
                +
                +struct Bar;
                +
                +impl Display for Bar {
                +    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
                +        f.write_str("this is a bar")
                +    }
                +}
                +
                +impl Default for Bar {
                +    fn default() -> Self {
                +        Bar // well, we have no other choice
                +    }
                +}
                +
                +impl DefaultishablyPrintable<i32> for Foo {}
                +
                +impl DefaultishablyPrintable<Bar> for Foo {}
                +
                +fn main() {
                +    <Foo as DefaultishablyPrintable<i32>>::defaultish_print();
                +    <Foo as DefaultishablyPrintable<Bar>>::defaultish_print();
                +}
                +
                +
                +

                (Download the source code for this example: generics_fun.rs)

                +

                Static vs dynamic dispatch

                +
                trait Speak {
                +    fn speak(&self) -> &'static str;
                +}
                +
                +struct Dog;
                +
                +impl Speak for Dog {
                +    fn speak(&self) -> &'static str {
                +        "Hau hau" // it's a Polish dog!
                +    }
                +}
                +
                +struct Human;
                +
                +impl Speak for Human {
                +    fn speak(&self) -> &'static str {
                +        "Hello world"
                +    }
                +}
                +
                +// It works like templates in C++
                +// A different function will be generated for each T during compilation
                +// This process is called "monomorphization"
                +fn static_dispatch<T: Speak>(speaking: &T) {
                +    println!("{}!", speaking.speak());
                +}
                +
                +// Only one copy of that function will exist in the compiled binary
                +fn dynamic_dispatch(speaking: &dyn Speak) {
                +    println!("{}!", speaking.speak());
                +}
                +
                +fn main() {
                +    let dog = Dog;
                +    let human = Human;
                +
                +    static_dispatch(&dog);
                +    static_dispatch(&human);
                +
                +    dynamic_dispatch(&dog);
                +    dynamic_dispatch(&human);
                +
                +    // The observable behavior is identical
                +    // Static dispatch in general is a bit faster,
                +    // because there is no need to perform a "vtable lookup".
                +    // But it can also result in bigger binary sizes.
                +}
                +
                +
                +

                (Download the source code for this example: static_dynamic_dispatch.rs)

                +

                Lifetimes

                +

                Going back to the lesson about ownership, if we try to compile the following code:

                +
                {
                +    let r;
                +
                +    {
                +        let x = 5;
                +        r = &x;
                +    }
                +
                +    println!("r: {}", r);
                +}
                +
                +

                we should expect to get an error:

                +
                error[E0597]: `x` does not live long enough
                +  --> src/main.rs:7:17
                +   |
                +7  |             r = &x;
                +   |                 ^^ borrowed value does not live long enough
                +8  |         }
                +   |         - `x` dropped here while still borrowed
                +9  |
                +10 |         println!("r: {}", r);
                +   |                           - borrow later used here
                +
                +

                Courtesy of the borrow checker, we didn't end up with a dangling reference. But what exactly is happening behind the scenes? Rust introduces a concept of annotated lifetimes, where the lifetime of each value is being marked and tracked by the checker. Let's look at some examples:

                +
                {
                +    let r;                  // ---------+-- 'a
                +                            //          |
                +    {                       //          |
                +        let x = 5;          // -+-- 'b  |
                +        r = &x;             //  |       |
                +    }                       // -+       |
                +                            //          |
                +    println!("r: {}", r);   //          |
                +}                           // ---------+
                +
                +
                {
                +    let x = 5;              // ----------+-- 'b
                +                            //           |
                +    let r = &x;             // --+-- 'a  |
                +                            //   |       |
                +    println!("r: {}", r);   //   |       |
                +                            // --+       |
                +}                           // ----------+
                +
                +

                Annotations

                +

                Let's consider the following code finding the longer out of two strings:

                +
                fn longest(x: &str, y: &str) -> &str {
                +    if x.len() > y.len() {
                +        x
                +    } else {
                +        y
                +    }
                +}
                +
                +fn main() {
                +    let string1 = String::from("abcd");
                +    let string2 = "xyz";
                +
                +    let result = longest(string1.as_str(), string2);
                +    println!("The longest string is {}", result);
                +}
                +
                +

                If we try to compile this, we will get an error:

                +
                error[E0106]: missing lifetime specifier
                + --> src/main.rs:9:33
                +  |
                +9 | fn longest(x: &str, y: &str) -> &str {
                +  |               ----     ----     ^ expected named lifetime parameter
                +  |
                +  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
                +help: consider introducing a named lifetime parameter
                +  |
                +9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
                +  |           ++++     ++          ++          ++
                +
                +

                This is because Rust doesn't know which of the two provided strings (x or y) will be returned from the function. And because they potentially have different lifetimes, the lifetime of what we are returning remains unclear to the compiler - it needs our help.

                +

                Rust provides syntax for specifying lifetimes. The lifetime parameter name from the example (a) doesn't have any concrete meaning - it's just an arbitrary name for this one lifetime.

                +
                &i32        // a reference
                +&'a i32     // a reference with an explicit lifetime
                +&'a mut i32 // a mutable reference with an explicit lifetime
                +
                +

                So, knowing this, let's address the compiler's demands.

                +
                fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
                +    if x.len() > y.len() {
                +        x
                +    } else {
                +        y
                +    }
                +}
                +
                +

                When working with lifetimes, our work will usually revolve around specifying relationships between lifetimes of different values so that the compiler can successfully reason about the program's safety. In the context of the example above, this signature means that both of the function's arguments and its output will live at least as long as lifetime 'a. In practice, this means that the output's lifetime will be equal to the smaller of the two inputs' lifetimes.

                +
                fn longest<'a>(first: &'a str, second: &'a str) -> &'a str {
                +    if first.len() > second.len() {
                +        first
                +    } else {
                +        second
                +    }
                +}
                +
                +fn main() {
                +    let string1 = String::from("long string is long");
                +
                +    {
                +        let string2 = String::from("xyz");
                +        let result = longest(string1.as_str(), string2.as_str());
                +        println!("The longest string is {}", result);
                +    }
                +
                +    // This doesn't compile - incorrect lifetimes
                +    //
                +    // let string1 = String::from("long string is long");
                +    // let result;
                +    // {
                +    //     let string2 = String::from("xyz");
                +    //     result = longest(string1.as_str(), string2.as_str());
                +    // }
                +    // println!("The longest string is {}", result);
                +}
                +
                +
                +

                (Download the source code for this example: lifetimes_basic.rs)

                +

                Trying to compile the second variant displeases the compiler (just like we hoped).

                +
                error[E0597]: `string2` does not live long enough
                + --> src/main.rs:6:44
                +  |
                +6 |         result = longest(string1.as_str(), string2.as_str());
                +  |                                            ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
                +7 |     }
                +  |     - `string2` dropped here while still borrowed
                +8 |     println!("The longest string is {}", result);
                +  |                                          ------ borrow later used here
                +
                +

                Lifetime elision

                +

                We now know how to explicitly write lifetime parameters, but you might recall that we don't always have to that. Indeed, Rust will first try to figure out the lifetimes itself, applying a set of predefined rules. We call this lifetime elision.

                +
                fn first_two(seq: &[u32]) -> &[u32] {
                +    if seq.len() < 2 {
                +        seq
                +    } else {
                +        &seq[..2]
                +    }
                +}
                +
                +fn main() {
                +    let seq = [1, 2, 3, 4];
                +
                +    println!(
                +        "First two elements of the sequence: {:?}",
                +        first_two(&seq[..])
                +    );
                +}
                +
                +
                +

                (Download the source code for this example: lifetimes_elision.rs)

                +

                The above works, even though we didn't specify any lifetime parameters at all. The reason lies in the rules we mentioned, which are as follows (where input lifetimes are lifetimes on parameters and output lifetimes are lifetimes on return values):

                +
                  +
                • +

                  Each parameter that is a reference gets its own lifetime parameter.

                  +
                • +
                • +

                  If there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters.

                  +
                • +
                • +

                  If there are multiple input lifetime parameters, but one of them is &self or &mut self, the lifetime of self is assigned to all output lifetime parameters.

                  +
                • +
                +

                Let's try to understand how the compiler inferred the lifetimes of our first_two functions. We start with the following signature:

                +
                fn first_two(seq: &[u32]) -> &[u32] {
                +
                +

                Then, we apply the first rule:

                +
                fn first_two<'a>(seq: &'a [u32]) -> &[u32] {
                +
                +

                Next, we check the second rule. It applies here as well.

                +
                fn first_two<'a>(seq: &'a [u32]) -> &'a [u32] {
                +
                +

                With that, we arrive at a state where all lifetimes are specified.

                +

                Static lifetime

                +

                There exists one special lifetime called 'static, which means that a reference can live for the entire duration of the program. All string literals are annotated with this lifetime as they are stored directly in the program's binary. Full type annotation of a string literal in Rust is therefore as follows:

                +
                let s: &'static str = "I have a static lifetime.";
                +
                +

                Trait + lifetimes - a challenging tandem

                +

                Let's go back to our basic_trait.rs example. The Summary trait was really wasteful: it always allocated the Strings on heap, even though we only needed to display the formatted string, and we could do that without allocations. How? By using Display trait, of course.

                +

                The simplest possible optimisation would be like this:

                +
                #![allow(dead_code)]
                +
                +use std::fmt::Display;
                +
                +struct NewsArticle {
                +    headline: String,
                +    location: String,
                +    author: String,
                +    content: String,
                +}
                +
                +impl Display for NewsArticle {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        write!(
                +            f,
                +            "{}, by {} ({})",
                +            self.headline, self.author, self.location
                +        )
                +    }
                +}
                +
                +struct Tweet {
                +    username: String,
                +    content: String,
                +}
                +
                +impl Display for Tweet {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        write!(f, "{}: {}", self.username, self.content)
                +    }
                +}
                +
                +fn main() {
                +    let tweet = Tweet {
                +        username: String::from("horse_ebooks"),
                +        content: String::from("of course, as you probably already know, people"),
                +    };
                +
                +    println!("1 new tweet: {}", tweet);
                +}
                +
                +
                +

                (Download the source code for this example: basic_trait_display.rs)

                +

                This eliminates the heap allocations, but there's another catch. What if NewsArticle already had another (non-summarizing) Display implementation? We would end up in a double-trait-implementation conflict, which is a compile-time error.

                +

                We can solve the one-type-one-trait-impl problem by introducing another type just for summarizing. The first attempt could be to use generics in traits:

                +
                #![allow(dead_code)]
                +
                +use std::fmt::Display;
                +
                +trait Summary<'a, Summarizer: Display> {
                +    fn summarize(&'a self) -> Summarizer;
                +}
                +
                +struct NewsArticle {
                +    headline: String,
                +    location: String,
                +    author: String,
                +    content: String,
                +}
                +
                +impl Display for NewsArticle {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        writeln!(
                +            f,
                +            "{}, by {} ({})",
                +            self.headline, self.author, self.location
                +        )?;
                +        f.write_str(&self.content)
                +    }
                +}
                +
                +struct NewsArticleSummarizer<'a>(&'a NewsArticle);
                +
                +impl Display for NewsArticleSummarizer<'_> {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        let article = self.0;
                +        write!(
                +            f,
                +            "{}, by {} ({})",
                +            article.headline, article.author, article.location
                +        )
                +    }
                +}
                +
                +impl<'a> Summary<'a, NewsArticleSummarizer<'a>> for NewsArticle {
                +    fn summarize(&'a self) -> NewsArticleSummarizer<'a> {
                +        NewsArticleSummarizer(self)
                +    }
                +}
                +
                +struct Tweet {
                +    username: String,
                +    content: String,
                +}
                +
                +struct TweetSummarizer<'a>(&'a Tweet);
                +
                +impl Display for TweetSummarizer<'_> {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        let tweet = self.0;
                +        write!(f, "{}: {}", tweet.username, tweet.content)
                +    }
                +}
                +
                +impl<'a> Summary<'a, TweetSummarizer<'a>> for Tweet {
                +    fn summarize(&'a self) -> TweetSummarizer<'a> {
                +        TweetSummarizer(self)
                +    }
                +}
                +
                +impl<'a> Summary<'a, NewsArticleSummarizer<'a>> for Tweet {
                +    fn summarize(&'a self) -> NewsArticleSummarizer<'a> {
                +        unimplemented!("This is only to make code type-check and compile.");
                +    }
                +}
                +
                +fn main() {
                +    let empty_article = NewsArticle {
                +        headline: "".into(),
                +        location: String::new(),
                +        author: String::default(),
                +        content: Default::default(),
                +    };
                +    println!("1 new article: {}", empty_article.summarize());
                +
                +    let tweet = Tweet {
                +        username: String::from("horse_ebooks"),
                +        content: String::from("of course, as you probably already know, people"),
                +    };
                +
                +    // Compile error: `type annotations needed; multiple `impl`s satisfying `Tweet: Summary<'_, _>` found`
                +    // println!("1 new tweet: {}", tweet.summarize());
                +    println!(
                +        "1 new tweet: {}",
                +        <Tweet as Summary<'_, TweetSummarizer>>::summarize(&tweet)
                +    );
                +    println!(
                +        "1 new tweet: {}",
                +        <Tweet as Summary<'_, NewsArticleSummarizer>>::summarize(&tweet)
                +    );
                +}
                +
                +
                +

                (Download the source code for this example: trait_generic_type.rs)

                +

                The problem here is that nothing hinders us from implement the trait (with various type parameters) for the same type, which leads to awkward ambiguity when calling the trait's methods (see main fn).

                +

                The use of generic types in Summary trait makes it semantics like this:

                +
                +

                A type can be summarized with any type supporting it.

                +
                +

                When we want the trait to require exactly one possible generic implementation for a given type, we can leverage associated types. Example here:

                +
                #![allow(dead_code)]
                +
                +use std::fmt::Display;
                +
                +trait Summary<'a> {
                +    type Summarizer: Display;
                +
                +    fn summarize(&'a self) -> Self::Summarizer;
                +}
                +
                +struct NewsArticle {
                +    headline: String,
                +    location: String,
                +    author: String,
                +    content: String,
                +}
                +
                +impl Display for NewsArticle {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        writeln!(
                +            f,
                +            "{}, by {} ({})",
                +            self.headline, self.author, self.location
                +        )?;
                +        f.write_str(&self.content)
                +    }
                +}
                +
                +struct NewsArticleSummarizer<'a>(&'a NewsArticle);
                +
                +impl Display for NewsArticleSummarizer<'_> {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        let article = self.0;
                +        write!(
                +            f,
                +            "{}, by {} ({})",
                +            article.headline, article.author, article.location
                +        )
                +    }
                +}
                +
                +impl<'a> Summary<'a> for NewsArticle {
                +    type Summarizer = NewsArticleSummarizer<'a>;
                +    fn summarize(&'a self) -> Self::Summarizer {
                +        NewsArticleSummarizer(self)
                +    }
                +}
                +
                +struct Tweet {
                +    username: String,
                +    content: String,
                +}
                +
                +struct TweetSummarizer<'a>(&'a Tweet);
                +
                +impl Display for TweetSummarizer<'_> {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        let tweet = self.0;
                +        write!(f, "{}: {}", tweet.username, tweet.content)
                +    }
                +}
                +
                +impl<'a> Summary<'a> for Tweet {
                +    type Summarizer = TweetSummarizer<'a>;
                +    fn summarize(&'a self) -> Self::Summarizer {
                +        TweetSummarizer(self)
                +    }
                +}
                +
                +fn main() {
                +    let tweet = Tweet {
                +        username: String::from("horse_ebooks"),
                +        content: String::from("of course, as you probably already know, people"),
                +    };
                +
                +    println!("1 new tweet: {}", tweet.summarize());
                +}
                +
                +
                +

                (Download the source code for this example: trait_associated_type.rs)

                +

                The use of associated types in Summary trait makes it semantics like this:

                +
                +

                A type can be summarized with at most one specific type.

                +
                +

                Yet another approach (arguably, the cleanest one) would be to use the impl trait syntax in a trait (quite recently stabilized!). +Example:

                +
                #![allow(dead_code)]
                +
                +use std::fmt::Display;
                +
                +trait Summary {
                +    fn summarize(&self) -> impl Display;
                +}
                +
                +struct NewsArticle {
                +    headline: String,
                +    location: String,
                +    author: String,
                +    content: String,
                +}
                +
                +impl Display for NewsArticle {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        writeln!(
                +            f,
                +            "{}, by {} ({})",
                +            self.headline, self.author, self.location
                +        )?;
                +        f.write_str(&self.content)
                +    }
                +}
                +
                +struct NewsArticleSummarizer<'a>(&'a NewsArticle);
                +
                +impl Display for NewsArticleSummarizer<'_> {
                +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +        let article = self.0;
                +        write!(
                +            f,
                +            "{}, by {} ({})",
                +            article.headline, article.author, article.location
                +        )
                +    }
                +}
                +
                +impl Summary for NewsArticle {
                +    fn summarize(&self) -> impl Display {
                +        NewsArticleSummarizer(self)
                +    }
                +}
                +
                +struct Tweet {
                +    username: String,
                +    content: String,
                +}
                +
                +impl Summary for Tweet {
                +    fn summarize(&self) -> impl Display {
                +        struct TweetSummarizer<'a>(&'a Tweet);
                +
                +        impl Display for TweetSummarizer<'_> {
                +            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                +                let tweet = self.0;
                +                write!(f, "{}: {}", tweet.username, tweet.content)
                +            }
                +        }
                +
                +        TweetSummarizer(self)
                +    }
                +}
                +
                +fn main() {
                +    let tweet = Tweet {
                +        username: String::from("horse_ebooks"),
                +        content: String::from("of course, as you probably already know, people"),
                +    };
                +
                +    println!("1 new tweet: {}", tweet.summarize());
                +}
                +
                +
                +

                (Download the source code for this example: impl_trait.rs)

                +

                Obligatory reading

                + +

                Assignment 3 (graded)

                +

                Passage Pathing

                +

                Deadline: 30.10.2024 23:59

                + + +
                +
                + + + + +
                + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/05-types-reasoning/lifetimes_basic.rs b/lessons/05-types-reasoning/lifetimes_basic.rs new file mode 100644 index 0000000..a4eaa2b --- /dev/null +++ b/lessons/05-types-reasoning/lifetimes_basic.rs @@ -0,0 +1,27 @@ +fn longest<'a>(first: &'a str, second: &'a str) -> &'a str { + if first.len() > second.len() { + first + } else { + second + } +} + +fn main() { + let string1 = String::from("long string is long"); + + { + let string2 = String::from("xyz"); + let result = longest(string1.as_str(), string2.as_str()); + println!("The longest string is {}", result); + } + + // This doesn't compile - incorrect lifetimes + // + // let string1 = String::from("long string is long"); + // let result; + // { + // let string2 = String::from("xyz"); + // result = longest(string1.as_str(), string2.as_str()); + // } + // println!("The longest string is {}", result); +} diff --git a/lessons/05-types-reasoning/lifetimes_elision.rs b/lessons/05-types-reasoning/lifetimes_elision.rs new file mode 100644 index 0000000..9633909 --- /dev/null +++ b/lessons/05-types-reasoning/lifetimes_elision.rs @@ -0,0 +1,16 @@ +fn first_two(seq: &[u32]) -> &[u32] { + if seq.len() < 2 { + seq + } else { + &seq[..2] + } +} + +fn main() { + let seq = [1, 2, 3, 4]; + + println!( + "First two elements of the sequence: {:?}", + first_two(&seq[..]) + ); +} diff --git a/lessons/05-types-reasoning/non_generic.rs b/lessons/05-types-reasoning/non_generic.rs new file mode 100644 index 0000000..c983e3b --- /dev/null +++ b/lessons/05-types-reasoning/non_generic.rs @@ -0,0 +1,35 @@ +fn largest_i32(list: &[i32]) -> i32 { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn largest_char(list: &[char]) -> char { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest_i32(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest_char(&char_list); + println!("The largest char is {}", result); +} diff --git a/lessons/05-types-reasoning/static_dynamic_dispatch.rs b/lessons/05-types-reasoning/static_dynamic_dispatch.rs new file mode 100644 index 0000000..2d9eeda --- /dev/null +++ b/lessons/05-types-reasoning/static_dynamic_dispatch.rs @@ -0,0 +1,47 @@ +trait Speak { + fn speak(&self) -> &'static str; +} + +struct Dog; + +impl Speak for Dog { + fn speak(&self) -> &'static str { + "Hau hau" // it's a Polish dog! + } +} + +struct Human; + +impl Speak for Human { + fn speak(&self) -> &'static str { + "Hello world" + } +} + +// It works like templates in C++ +// A different function will be generated for each T during compilation +// This process is called "monomorphization" +fn static_dispatch(speaking: &T) { + println!("{}!", speaking.speak()); +} + +// Only one copy of that function will exist in the compiled binary +fn dynamic_dispatch(speaking: &dyn Speak) { + println!("{}!", speaking.speak()); +} + +fn main() { + let dog = Dog; + let human = Human; + + static_dispatch(&dog); + static_dispatch(&human); + + dynamic_dispatch(&dog); + dynamic_dispatch(&human); + + // The observable behavior is identical + // Static dispatch in general is a bit faster, + // because there is no need to perform a "vtable lookup". + // But it can also result in bigger binary sizes. +} diff --git a/lessons/05-types-reasoning/trait_associated_type.rs b/lessons/05-types-reasoning/trait_associated_type.rs new file mode 100644 index 0000000..1c108bf --- /dev/null +++ b/lessons/05-types-reasoning/trait_associated_type.rs @@ -0,0 +1,77 @@ +#![allow(dead_code)] + +use std::fmt::Display; + +trait Summary<'a> { + type Summarizer: Display; + + fn summarize(&'a self) -> Self::Summarizer; +} + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Display for NewsArticle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "{}, by {} ({})", + self.headline, self.author, self.location + )?; + f.write_str(&self.content) + } +} + +struct NewsArticleSummarizer<'a>(&'a NewsArticle); + +impl Display for NewsArticleSummarizer<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let article = self.0; + write!( + f, + "{}, by {} ({})", + article.headline, article.author, article.location + ) + } +} + +impl<'a> Summary<'a> for NewsArticle { + type Summarizer = NewsArticleSummarizer<'a>; + fn summarize(&'a self) -> Self::Summarizer { + NewsArticleSummarizer(self) + } +} + +struct Tweet { + username: String, + content: String, +} + +struct TweetSummarizer<'a>(&'a Tweet); + +impl Display for TweetSummarizer<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let tweet = self.0; + write!(f, "{}: {}", tweet.username, tweet.content) + } +} + +impl<'a> Summary<'a> for Tweet { + type Summarizer = TweetSummarizer<'a>; + fn summarize(&'a self) -> Self::Summarizer { + TweetSummarizer(self) + } +} + +fn main() { + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + println!("1 new tweet: {}", tweet.summarize()); +} diff --git a/lessons/05-types-reasoning/trait_default.rs b/lessons/05-types-reasoning/trait_default.rs new file mode 100644 index 0000000..84ba1b3 --- /dev/null +++ b/lessons/05-types-reasoning/trait_default.rs @@ -0,0 +1,67 @@ +#![allow(dead_code)] + +struct Upload { + filename: String, +} + +#[allow(dead_code)] +struct Photo { + filename: String, + width: u32, + height: u32, +} + +trait Description { + fn describe(&self) -> String { + String::from("No description available.") + } +} + +// All default implementations +impl Description for Upload {} + +// Default implementations can be overwritten +impl Description for Photo { + fn describe(&self) -> String { + format!("{} ({} x {})", self.filename, self.width, self.height) + } +} + +// Default implementations can rely on methods with no defaults +trait Size { + fn width(&self) -> u32; + fn height(&self) -> u32; + + fn size(&self) -> u32 { + self.width() * self.height() + } +} + +impl Size for Photo { + fn width(&self) -> u32 { + self.width + } + + fn height(&self) -> u32 { + self.height + } + + // Using default impl of `size()` +} + +fn main() { + let upload = Upload { + filename: String::from("notes.txt"), + }; + + println!("Upload: {}", upload.describe()); + + let photo = Photo { + filename: String::from("stock_crustacean.png"), + width: 100, + height: 150, + }; + + println!("Photo: {}", photo.describe()); + println!("Size: {}", photo.size()); +} diff --git a/lessons/05-types-reasoning/trait_generic_type.rs b/lessons/05-types-reasoning/trait_generic_type.rs new file mode 100644 index 0000000..dea0170 --- /dev/null +++ b/lessons/05-types-reasoning/trait_generic_type.rs @@ -0,0 +1,96 @@ +#![allow(dead_code)] + +use std::fmt::Display; + +trait Summary<'a, Summarizer: Display> { + fn summarize(&'a self) -> Summarizer; +} + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Display for NewsArticle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "{}, by {} ({})", + self.headline, self.author, self.location + )?; + f.write_str(&self.content) + } +} + +struct NewsArticleSummarizer<'a>(&'a NewsArticle); + +impl Display for NewsArticleSummarizer<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let article = self.0; + write!( + f, + "{}, by {} ({})", + article.headline, article.author, article.location + ) + } +} + +impl<'a> Summary<'a, NewsArticleSummarizer<'a>> for NewsArticle { + fn summarize(&'a self) -> NewsArticleSummarizer<'a> { + NewsArticleSummarizer(self) + } +} + +struct Tweet { + username: String, + content: String, +} + +struct TweetSummarizer<'a>(&'a Tweet); + +impl Display for TweetSummarizer<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let tweet = self.0; + write!(f, "{}: {}", tweet.username, tweet.content) + } +} + +impl<'a> Summary<'a, TweetSummarizer<'a>> for Tweet { + fn summarize(&'a self) -> TweetSummarizer<'a> { + TweetSummarizer(self) + } +} + +impl<'a> Summary<'a, NewsArticleSummarizer<'a>> for Tweet { + fn summarize(&'a self) -> NewsArticleSummarizer<'a> { + unimplemented!("This is only to make code type-check and compile."); + } +} + +fn main() { + let empty_article = NewsArticle { + headline: "".into(), + location: String::new(), + author: String::default(), + content: Default::default(), + }; + println!("1 new article: {}", empty_article.summarize()); + + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + // Compile error: `type annotations needed; multiple `impl`s satisfying `Tweet: Summary<'_, _>` found` + // println!("1 new tweet: {}", tweet.summarize()); + println!( + "1 new tweet: {}", + >::summarize(&tweet) + ); + println!( + "1 new tweet: {}", + >::summarize(&tweet) + ); +} diff --git a/lessons/06-closures-iterators/closures_capturing.rs b/lessons/06-closures-iterators/closures_capturing.rs new file mode 100644 index 0000000..c42a640 --- /dev/null +++ b/lessons/06-closures-iterators/closures_capturing.rs @@ -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::>(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) + 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| 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); +} diff --git a/lessons/06-closures-iterators/closures_fun.rs b/lessons/06-closures-iterators/closures_fun.rs new file mode 100644 index 0000000..9f2ae91 --- /dev/null +++ b/lessons/06-closures-iterators/closures_fun.rs @@ -0,0 +1,64 @@ +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). + // This will give us `std::function` -like experience. + } + + // 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()); + } +} diff --git a/lessons/06-closures-iterators/closures_syntax.rs b/lessons/06-closures-iterators/closures_syntax.rs new file mode 100644 index 0000000..4b07bd2 --- /dev/null +++ b/lessons/06-closures-iterators/closures_syntax.rs @@ -0,0 +1,20 @@ +fn main() { + #[rustfmt::skip] + { + // This is formatted so that without 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); + }; +} diff --git a/lessons/06-closures-iterators/index.html b/lessons/06-closures-iterators/index.html new file mode 100644 index 0000000..e99ad45 --- /dev/null +++ b/lessons/06-closures-iterators/index.html @@ -0,0 +1,536 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                + + +
                + +
                + +
                +
                +
                  +
                  +
                  + +
                  + +

                  Closures and Iterators

                  +

                  + 2024-10-31 (last edit: 2024-10-30) +

                  +

                  Closures

                  +

                  Closures (Polish: "domknięcia") are anonymous functions that can access variables from the scope in which they were defined.

                  +

                  Closure syntax

                  +
                  fn main() {
                  +    #[rustfmt::skip]
                  +    {
                  +        // This is formatted so that without 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);
                  +    };
                  +}
                  +
                  +
                  +

                  (Download the source code for this example: closures_syntax.rs)

                  +

                  Closures' types

                  +

                  Closures are unnameable types. That is, each closure gets its own unique type from the compiler, +but we cannot name it. Therefore, closures' types must be inferred. +We will often use impl keyword with closure traits (e.g., impl Fn) - those traits are described below.

                  +

                  Closures capture environment

                  +

                  Closures can capture variables from the environment where they are defined. They can do that in two ways:

                  +
                    +
                  • Capturing References (borrowing), or
                  • +
                  • Moving Ownership.
                  • +
                  +

                  HOW closures capture variables is one thing. +But even more important is WHAT closures do with their captures.

                  +

                  Functions & closures hierarchy

                  +

                  Based on WHAT a closure does with its captures, it implements closure traits:

                  +
                    +
                  • FnOnce - closures that may move out of their captures environment (and thus called once).
                  • +
                  • FnMut - closures that may mutate their captures, but don't move out of their captures environment (so can be called multiple times, but require a mutable reference);
                  • +
                  • Fn - closures that do not mutate their captures (so can be called multiple times through an immutable reference).
                  • +
                  +

                  For completeness, there is a (concrete) type of function pointers:

                  +
                    +
                  • fn - functions, closures with no captures.
                  • +
                  +

                  Those traits and the fn type form a hierarchy: fnFnFnMutFnOnce

                  + $$ fn \subseteq Fn \subseteq FnMut \subseteq FnOnce $$ --> +

                  The following code sample demonstrates various ways to capture environment (borrowing or moving) and various kinds of closures, based on what they do with their captures:

                  +
                  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);
                  +}
                  +
                  +
                  +

                  (Download the source code for this example: closures_capturing.rs)

                  +

                  Closures as trait objects (in dynamic dispatch)

                  +

                  The following code sample shows how one can use closures as dyn Trait objects, bypassing the problem of them having anonymous types:

                  +
                  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).
                  +        // This will give us `std::function` -like experience.
                  +    }
                  +
                  +    // 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());
                  +    }
                  +}
                  +
                  +
                  +

                  (Download the source code for this example: closures_fun.rs)

                  +

                  Examples

                  +

                  We'll go through the examples from Rust by Example. +More examples will be seen when working with iterators.

                  +

                  Iterators

                  +

                  In Rust, there is no hierarchy of types for collections (because there is no inheritance in general). +Instead, what makes a collection is that it can be iterated over.

                  +

                  A usual way in Rust to perform an iteration over something, be it a range of values or items in a collection, is creating a (lazy) iterator over it and transforming it using iterator adaptors. For example, if T: Iterator, then T::map() creates a Map<T> adaptor. Once a final iterator is created, it has to be actually activated (iterated over), which is most commonly done by:

                  +
                    +
                  • exhausting it with the for loop,
                  • +
                  • manually iterating over it using next() calls,
                  • +
                  • collecting its contents into inferred collection (collect()),
                  • +
                  • consuming it with a consuming adaptor (e.g., sum(), count),
                  • +
                  +
                  use std::collections::HashSet;
                  +
                  +fn main() {
                  +    // Various ways to create a String.
                  +    let mut strings = [
                  +        String::new(),
                  +        String::from("a"),
                  +        "b".into(),
                  +        "c".to_owned(),
                  +        "d".to_string(),
                  +        "e".chars().collect(),
                  +    ];
                  +
                  +    // `iter()` is a usual method that creates an iterator over immutable references to the collection's items.
                  +    let _all_len_0_or_1 = strings
                  +        .iter()
                  +        .filter(|s| !s.is_empty())
                  +        .all(|s| s.len() == 1);
                  +
                  +    // `iter_mut()` is a usual method that creates an iterator over mutable references to the collection's items.
                  +    for s in strings.iter_mut().map_while(|s| match s.as_str() {
                  +        "c" => None,
                  +        _ => Some(s),
                  +    }) {
                  +        *s = s.replace("b", "aba");
                  +    }
                  +
                  +    // This code is equivalent to the `for` above.
                  +    // `for` is usually more idiomatic, but `for_each` is sometimes cleaner and sometimes faster.
                  +    strings
                  +        .iter_mut()
                  +        .map_while(|s| match s.as_str() {
                  +            "c" => None,
                  +            _ => Some(s),
                  +        })
                  +        .for_each(|s| *s = s.replace("b", "aba"));
                  +
                  +    // `into_iter()` is a method from `IntoIterator` trait that converts a collection to an iterator
                  +    let mut empty_strings_iter = strings.into_iter().map(|mut s| {
                  +        s.clear();
                  +        s
                  +    });
                  +
                  +    // This is a set of empty Strings...
                  +    let empty_strings_set = empty_strings_iter.clone().collect::<HashSet<_>>();
                  +
                  +    // And this is a Vec of immutable references to empty Strings.
                  +    let empty_string_refs_vec = empty_strings_set.iter().collect::<Vec<_>>();
                  +
                  +    // equivalent to `empty_string_refs_vec.into_iter()`
                  +    for s in empty_string_refs_vec {
                  +        println!("{}", s)
                  +    }
                  +
                  +    while let Some(s) = empty_strings_iter.next_back() {
                  +        assert!(s.is_empty());
                  +    }
                  +}
                  +
                  +
                  +

                  (Download the source code for this example: iterator_exhaustion.rs)

                  +

                  Iterators are highly optimised, so they are high-level code that compiles down to simple and optimised machine code (intended as zero-cost abstractions).

                  +

                  We'll go through the official docs.

                  +
                    +
                  • Most methods are defined in the Iterator trait.
                  • +
                  • IntoIterator is also worth noting, because it makes types work with the for loop.
                  • +
                  • For completeness, there is FromIterator, which is required for collect() to work.
                  • +
                  +

                  Reading

                  + +

                  Assignment 4 (graded)

                  +

                  Lazy

                  +

                  Deadline: 06.11.2024 23:59

                  + + +
                  +
                  + + + + +
                  + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/06-closures-iterators/iterator_exhaustion.rs b/lessons/06-closures-iterators/iterator_exhaustion.rs new file mode 100644 index 0000000..7374cd3 --- /dev/null +++ b/lessons/06-closures-iterators/iterator_exhaustion.rs @@ -0,0 +1,58 @@ +use std::collections::HashSet; + +fn main() { + // Various ways to create a String. + let mut strings = [ + String::new(), + String::from("a"), + "b".into(), + "c".to_owned(), + "d".to_string(), + "e".chars().collect(), + ]; + + // `iter()` is a usual method that creates an iterator over immutable references to the collection's items. + let _all_len_0_or_1 = strings + .iter() + .filter(|s| !s.is_empty()) + .all(|s| s.len() == 1); + + // `iter_mut()` is a usual method that creates an iterator over mutable references to the collection's items. + for s in strings.iter_mut().map_while(|s| match s.as_str() { + "c" => None, + _ => Some(s), + }) { + *s = s.replace("b", "aba"); + } + + // This code is equivalent to the `for` above. + // `for` is usually more idiomatic, but `for_each` is sometimes cleaner and sometimes faster. + strings + .iter_mut() + .map_while(|s| match s.as_str() { + "c" => None, + _ => Some(s), + }) + .for_each(|s| *s = s.replace("b", "aba")); + + // `into_iter()` is a method from `IntoIterator` trait that converts a collection to an iterator + let mut empty_strings_iter = strings.into_iter().map(|mut s| { + s.clear(); + s + }); + + // This is a set of empty Strings... + let empty_strings_set = empty_strings_iter.clone().collect::>(); + + // And this is a Vec of immutable references to empty Strings. + let empty_string_refs_vec = empty_strings_set.iter().collect::>(); + + // equivalent to `empty_string_refs_vec.into_iter()` + for s in empty_string_refs_vec { + println!("{}", s) + } + + while let Some(s) = empty_strings_iter.next_back() { + assert!(s.is_empty()); + } +} diff --git a/lessons/07-smart-pointers/box.rs b/lessons/07-smart-pointers/box.rs new file mode 100644 index 0000000..9a9f99e --- /dev/null +++ b/lessons/07-smart-pointers/box.rs @@ -0,0 +1,18 @@ +fn box_simple() { + let b = Box::new(5); + println!("b = {}", b); + + let _x = 10 + *b; +} + +// `Box` gives us the indirection required to define +// recursive types +#[allow(dead_code)] +enum List { + Cons(i32, Box), + Nil, +} + +fn main() { + box_simple(); +} diff --git a/lessons/07-smart-pointers/deref_coercion.rs b/lessons/07-smart-pointers/deref_coercion.rs new file mode 100644 index 0000000..c5b14c7 --- /dev/null +++ b/lessons/07-smart-pointers/deref_coercion.rs @@ -0,0 +1,39 @@ +use std::ops::Deref; + +struct MyBox(T); + +// We won't be allocating anything on the heap here as it is not important here. +// We're only focusing on the dereference mechanisms. +impl MyBox { + fn new(x: T) -> MyBox { + MyBox(x) + } +} + +impl Deref for MyBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn hello(name: &str) { + println!("Hello, {}!", name); +} + +fn main() { + let x = 5; + let int_box = MyBox::new(x); + + assert_eq!(5, *int_box); + + // String also implements the `Deref` trait. + // In fact, String actually is a smart pointer. + let s = String::from("I'm a smart pointer too"); + hello(&s); + + // Deref coercion can deal with multiple levels of indirection. + let str_box = MyBox::new(String::from("Rust")); + hello(&str_box); +} diff --git a/lessons/07-smart-pointers/index.html b/lessons/07-smart-pointers/index.html new file mode 100644 index 0000000..d8607c6 --- /dev/null +++ b/lessons/07-smart-pointers/index.html @@ -0,0 +1,417 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                  + + +
                  + +
                  + +
                  +
                  +
                    +
                    +
                    + +
                    + +

                    Smart Pointers

                    +

                    + 2024-11-07 (last edit: 2022-11-21) +

                    +

                    Working with the heap

                    +

                    So far we've only used heap allocated memory indirectly by working with containers such as vectors, maps or the String type, otherwise allocating our variables on the stack. We didn't really have to be aware of the fact that these collections used the heap, as all that memory management details were hidden away from us. In this lesson we'll take a closer look at what is really happening there and how we can do that ourselves.

                    +

                    To work with heap-allocated memory, Rust features smart pointers. You should have already heard this term as it is a very important feature in C++ and the concept is virtually the same here - they are wrappers around raw allocated memory that provide additional, safety-ensuring mechanism. What defines a smart pointer in Rust is generally the implementation of two traits: Drop and Deref.

                    +

                    The Drop trait is pretty straightforward as it consists of one method - fn drop(&mut self) - that is, basically, the destructor, invoked during stack unwinding.

                    +

                    The Deref trait allows us to overload the dereference (*) operator.

                    +

                    Deref coercion

                    +

                    Apart from enabling access to the underlying value, implementing the Deref trait enables Rust to perform deref coercion on the pointer - trying to remove as many levels of indirection as it can. What it means in practice is that we will be able to use it with any code working on plain references.

                    +
                    use std::ops::Deref;
                    +
                    +struct MyBox<T>(T);
                    +
                    +// We won't be allocating anything on the heap here as it is not important here.
                    +// We're only focusing on the dereference mechanisms.
                    +impl<T> MyBox<T> {
                    +    fn new(x: T) -> MyBox<T> {
                    +        MyBox(x)
                    +    }
                    +}
                    +
                    +impl<T> Deref for MyBox<T> {
                    +    type Target = T;
                    +
                    +    fn deref(&self) -> &Self::Target {
                    +        &self.0
                    +    }
                    +}
                    +
                    +fn hello(name: &str) {
                    +    println!("Hello, {}!", name);
                    +}
                    +
                    +fn main() {
                    +    let x = 5;
                    +    let int_box = MyBox::new(x);
                    +
                    +    assert_eq!(5, *int_box);
                    +
                    +    // String also implements the `Deref` trait.
                    +    // In fact, String actually is a smart pointer.
                    +    let s = String::from("I'm a smart pointer too");
                    +    hello(&s);
                    +
                    +    // Deref coercion can deal with multiple levels of indirection.
                    +    let str_box = MyBox::new(String::from("Rust"));
                    +    hello(&str_box);
                    +}
                    +
                    +
                    +

                    (Download the source code for this example: deref_coercion.rs)

                    +

                    In general, there are three possible coercions that Rust can perform:

                    +
                      +
                    • +

                      From &T to &U when T: Deref<Target=U>

                      +
                    • +
                    • +

                      From &mut T to &mut U when T: DerefMut<Target=U>

                      +
                    • +
                    • +

                      From &mut T to &U when T: Deref<Target=U>

                      +
                    • +
                    +

                    While the first two coercions are straightforward, the third one is possible because treating a mutable reference as an immutable one does not break the rules of ownership.

                    +

                    Box - simple wrapper

                    +

                    The Box<T> type is the most basic out of Rust's smart pointers, equivalent to C++'s std::unique_ptr<T>. It's a simple wrapper that makes sure the underlying memory gets allocated and freed properly.

                    +
                    fn box_simple() {
                    +    let b = Box::new(5);
                    +    println!("b = {}", b);
                    +
                    +    let _x = 10 + *b;
                    +}
                    +
                    +// `Box` gives us the indirection required to define
                    +// recursive types
                    +#[allow(dead_code)]
                    +enum List {
                    +    Cons(i32, Box<List>),
                    +    Nil,
                    +}
                    +
                    +fn main() {
                    +    box_simple();
                    +}
                    +
                    +
                    +

                    (Download the source code for this example: box.rs)

                    +

                    Reference counting

                    +

                    The Rc<T> type is the equivalent of std::shared_ptr<T> from C++. There is one caveat to this though - because we're creating multiple references to the same object, those references have to be immutable in accordance with the ownership rules.

                    +
                    use std::rc::Rc;
                    +
                    +struct LoudInt(i32);
                    +
                    +impl Drop for LoudInt {
                    +    fn drop(&mut self) {
                    +        println!("[{}] Farewell!", self.0);
                    +    }
                    +}
                    +
                    +fn main() {
                    +    {
                    +        let outer_ref;
                    +
                    +        {
                    +            let inner_ref = Rc::new(LoudInt(5));
                    +
                    +            // strong_count represents the number of owning references pointing
                    +            // to data
                    +            assert_eq!(Rc::strong_count(&inner_ref), 1);
                    +
                    +            outer_ref = Rc::clone(&inner_ref);
                    +
                    +            assert_eq!(Rc::strong_count(&inner_ref), Rc::strong_count(&outer_ref));
                    +            assert_eq!(Rc::strong_count(&inner_ref), 2);
                    +        }
                    +
                    +        println!("The {} still lives!", outer_ref.0);
                    +        assert_eq!(Rc::strong_count(&outer_ref), 1);
                    +    }
                    +}
                    +
                    +
                    +

                    (Download the source code for this example: ref_count.rs)

                    +

                    Rust also provides a non-owning pointer in the form of Weak<T> (equivalent to std::weak_ptr<T>) that can be obtained from an instance of Rc<T>.

                    +
                    use std::rc::Rc;
                    +
                    +struct LoudInt(i32);
                    +
                    +impl Drop for LoudInt {
                    +    fn drop(&mut self) {
                    +        println!("[{}] Farewell!", self.0);
                    +    }
                    +}
                    +
                    +fn main() {
                    +    let weak_ref;
                    +
                    +    {
                    +        let shared_ref = Rc::new(LoudInt(5));
                    +
                    +        // weak_count keeps track of the non-owning reference to the data
                    +        assert_eq!(Rc::weak_count(&shared_ref), 0);
                    +
                    +        // `downgrade()` obtains a weak pointer to Rc's data
                    +        weak_ref = Rc::downgrade(&shared_ref);
                    +
                    +        assert_eq!(Rc::weak_count(&shared_ref), 1);
                    +        assert_eq!(Rc::strong_count(&shared_ref), 1);
                    +
                    +        // In order to use the the data underneath the weak pointer
                    +        // we need to obtain a new shared pointer from it.
                    +        // The `upgrade()` method returns `Option<Rc<T>>`.
                    +        let temp = weak_ref.upgrade();
                    +        assert_eq!(Rc::strong_count(&shared_ref), 2);
                    +        println!("The value is {}", temp.unwrap().0);
                    +    }
                    +
                    +    println!("The value should be deallocated by now.");
                    +    assert!(weak_ref.upgrade().is_none());
                    +}
                    +
                    +
                    +

                    (Download the source code for this example: weak_ref.rs)

                    +

                    Mutating the immutable

                    +

                    Good examples and explanation of the interior mutability pattern and runtime borrow checking can be found in the book.

                    +

                    Alongside the RefCell<T> type described above, there is an analogous Cell<T> type that operates on values instead of references.

                    +

                    Convenient handling of dyn objects

                    +

                    In previous labs you learned about dynamic dispatch and its strengths. The largest drawback you noticed is most likely that they are unsized (!Sized, where ! being syntax signifying lack of trait implementation).

                    +

                    When storing an object on a heap, however, we can use it as a dyn object seamlessly.

                    +

                    Obligatory reading

                    + +

                    Additional reading

                    + +

                    Assignment 5 (graded)

                    +

                    Corporations

                    +

                    Deadline: 13.11.2024 23:59

                    + + +
                    +
                    + + + + +
                    + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/07-smart-pointers/ref_count.rs b/lessons/07-smart-pointers/ref_count.rs new file mode 100644 index 0000000..0f97932 --- /dev/null +++ b/lessons/07-smart-pointers/ref_count.rs @@ -0,0 +1,31 @@ +use std::rc::Rc; + +struct LoudInt(i32); + +impl Drop for LoudInt { + fn drop(&mut self) { + println!("[{}] Farewell!", self.0); + } +} + +fn main() { + { + let outer_ref; + + { + let inner_ref = Rc::new(LoudInt(5)); + + // strong_count represents the number of owning references pointing + // to data + assert_eq!(Rc::strong_count(&inner_ref), 1); + + outer_ref = Rc::clone(&inner_ref); + + assert_eq!(Rc::strong_count(&inner_ref), Rc::strong_count(&outer_ref)); + assert_eq!(Rc::strong_count(&inner_ref), 2); + } + + println!("The {} still lives!", outer_ref.0); + assert_eq!(Rc::strong_count(&outer_ref), 1); + } +} diff --git a/lessons/07-smart-pointers/weak_ref.rs b/lessons/07-smart-pointers/weak_ref.rs new file mode 100644 index 0000000..6fa8e79 --- /dev/null +++ b/lessons/07-smart-pointers/weak_ref.rs @@ -0,0 +1,36 @@ +use std::rc::Rc; + +struct LoudInt(i32); + +impl Drop for LoudInt { + fn drop(&mut self) { + println!("[{}] Farewell!", self.0); + } +} + +fn main() { + let weak_ref; + + { + let shared_ref = Rc::new(LoudInt(5)); + + // weak_count keeps track of the non-owning reference to the data + assert_eq!(Rc::weak_count(&shared_ref), 0); + + // `downgrade()` obtains a weak pointer to Rc's data + weak_ref = Rc::downgrade(&shared_ref); + + assert_eq!(Rc::weak_count(&shared_ref), 1); + assert_eq!(Rc::strong_count(&shared_ref), 1); + + // In order to use the the data underneath the weak pointer + // we need to obtain a new shared pointer from it. + // The `upgrade()` method returns `Option>`. + let temp = weak_ref.upgrade(); + assert_eq!(Rc::strong_count(&shared_ref), 2); + println!("The value is {}", temp.unwrap().0); + } + + println!("The value should be deallocated by now."); + assert!(weak_ref.upgrade().is_none()); +} diff --git a/lessons/08-feedback-2/index.html b/lessons/08-feedback-2/index.html new file mode 100644 index 0000000..927d4e1 --- /dev/null +++ b/lessons/08-feedback-2/index.html @@ -0,0 +1,256 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                    + + +
                    + +
                    + +
                    +
                    +
                      +
                      +
                      + +
                      + +

                      Feedback #2

                      +

                      + 2022-11-21 (last edit: 2022-11-21) +

                      +

                      Feedback

                      +

                      Conditional implementation

                      +
                      impl<const N: usize> Shape for SphereN<N> {
                      +    type Volume = VolumeN<N>;
                      +    fn volume(&self) -> Self::Volume {
                      +        let mut volume: u32 = (f64::from(self.radius) * f64::from(self.radius) * PI) as u32;
                      +        if N == 3 {
                      +            volume = (f64::from(self.radius)
                      +                * f64::from(self.radius)
                      +                * f64::from(self.radius)
                      +                * PI
                      +                * 4.0_f64
                      +                / 3.0_f64) as u32;
                      +        }
                      +        Self::Volume::new(volume)
                      +    }
                      +}
                      +
                      +

                      Instead of checking N == 3, you can provide different impls for SphereN<2> and +SphereN<3> (as they are different types).

                      +

                      u32 and u64

                      +

                      They are different types, but because you can easily cast one to another, +it was not sufficient to make the implementation type-safe.

                      + + +
                      +
                      + + + + +
                      + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/09-concurrency/index.html b/lessons/09-concurrency/index.html new file mode 100644 index 0000000..b3a7cc6 --- /dev/null +++ b/lessons/09-concurrency/index.html @@ -0,0 +1,389 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                      + + +
                      + +
                      + +
                      +
                      +
                        +
                        +
                        + +
                        + +

                        Fearless concurrency

                        +

                        + 2024-11-14 (last edit: 2024-11-14) +

                        +

                        Parallelism vs Concurrency

                        +

                        Concurrency is when tasks can make progress independently of each other.

                        +

                        Parallelism is when multiple tasks make progress at the same time.

                        +

                        Concurrency models in Rust

                        +

                        Threads

                        +

                        Nothing unusual here.

                        +

                        Threads can be created with the thread::spawn function docs - please read them!.

                        +

                        This method returns a JoinHandle<T> which can be used to wait for the thread to finish. T is the type of the thread's return value.

                        +

                        Another way to spawn threads is using scope. Threads created in such way are mandatorily joined at the end of the scope, which guarantees that they will borrow items for no longer that the lifetime of the scope. Hence, they can borrow non-'static items!

                        +

                        Propagating panics

                        +

                        In Rust a panic of one thread doesn't affect the other threads (similar to how Java handles exceptions in threads).

                        +

                        Closures

                        +

                        Closures which are used to create threads must take ownership of any values they use. It can be forced with the move keyword.

                        +
                        use std::thread;
                        +
                        +fn main() {
                        +    let v = vec![1, 2, 3];
                        +
                        +    let handle = thread::spawn(move || {
                        +        println!("Here's a vector: {:?}", v);
                        +    });
                        +
                        +    handle.join().unwrap();
                        +}
                        +
                        +

                        Normal ownership rules still apply. It means that we cannot mutate the vector in the spawned thread from the main thread!

                        +

                        But what if we need to share some state?

                        +

                        Send and Sync

                        +

                        They are marker traits used to indicate that a type or a reference to it can be used across threads. See the nomicon for more information.

                        +
                        +
                          +
                        • A type is Send if it is safe to move it (send it) to another thread.
                        • +
                        • A type is Sync if it is safe to share (sync) between threads (T is Sync if and only if &T is Send).
                        • +
                        +
                        +

                        This makes sense, because Sync is about sharing object between threads, and & is the shared reference.

                        +

                        There is also a great answer on Rust forum, listing + explaining example types that are !Send or !Sync.

                        +

                        For more convenient analysis, examples are listed here:

                        +

                        Send + !Sync:

                        +
                          +
                        • UnsafeCell (=> Cell, RefCell);
                        • +
                        +

                        !Send + !Sync:

                        +
                          +
                        • Rc
                        • +
                        • *const T, *mut T (raw pointers)
                        • +
                        +

                        !Send + Sync:

                        +
                          +
                        • MutexGuard (hint: !Send for POSIX reasons)
                        • +
                        +

                        Exercise for the reader: explain reasons for all limitations of the above types.

                        +

                        Sharing state between threads

                        +

                        Message passing

                        +

                        One possible way is to use message passing. We can use a blocking queue (called mpsc - "multi producer single consumer FIFO queue") to do it. +We talked about blocking queues in the Concurrent programming class. In Rust, they are strongly-typed. Sending and receiving ends have different types.

                        +

                        Mutexes

                        +

                        In Rust, a mutex wraps a value and makes it thread-safe. +Because it becomes a part of the type, it's impossible to access the underlying value in an unsynchronized manner. It is conceptually similar to the RefCell type.

                        +

                        Arc is a smart pointer like Rc but it can be shared between threads.

                        +

                        Please read more about them in the book.

                        +

                        The docs also mention poisoning.

                        +

                        RwLocks

                        +

                        RwLocks are similar to mutexes, but they distinguish between read and write locks.

                        +

                        Atomic types

                        +

                        Atomic types are described in the docs.

                        +
                        use std::sync::Arc;
                        +use std::sync::atomic::{AtomicUsize, Ordering};
                        +use std::{hint, thread};
                        +
                        +fn main() {
                        +    let spinlock = Arc::new(AtomicUsize::new(1));
                        +
                        +    let spinlock_clone = Arc::clone(&spinlock);
                        +    let thread = thread::spawn(move|| {
                        +        spinlock_clone.store(0, Ordering::SeqCst);
                        +    });
                        +
                        +    // Wait for the other thread to release the lock
                        +    while spinlock.load(Ordering::SeqCst) != 0 {
                        +        hint::spin_loop();
                        +    }
                        +
                        +    if let Err(panic) = thread.join() {
                        +        println!("Thread had an error: {:?}", panic);
                        +    }
                        +}
                        +
                        +

                        Note that atomic values don't have to be wrapped in a mutex when shared across threads.

                        +

                        Wait...

                        +

                        If most types are Sync + Send, then what stops us from using a standard, non-atomic integer in the example above?

                        +
                        let spinlock = Arc::new(1);
                        +
                        +let spinlock_clone = Arc::clone(&spinlock);
                        +let thread = thread::spawn(move|| {
                        +    *spinlock_clone += 1;
                        +});
                        +
                        +while *spinlock != 0 {
                        +    hint::spin_loop();
                        +}
                        +
                        +
                        error[E0594]: cannot assign to data in an `Arc`
                        + --> src/main.rs:9:9
                        +  |
                        +9 |         *spinlock_clone += 1;
                        +  |         ^^^^^^^^^^^^^^^^^^^^ cannot assign
                        +  |
                        +  = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<i32>`
                        +
                        +

                        ...so we would have to use a RefCell to be able to modify the value through a shared reference...

                        +
                        let spinlock = Arc::new(RefCell::new(1));
                        +
                        +let spinlock_clone = Arc::clone(&spinlock);
                        +let thread = thread::spawn(move|| {
                        +    *spinlock_clone.borrow_mut() += 1;
                        +});
                        +
                        +// Wait for the other thread to release the lock
                        +while *spinlock.borrow() != 0 {
                        +    hint::spin_loop();
                        +}
                        +
                        +

                        ...but RefCell isn't Sync:

                        +
                        error[E0277]: `RefCell<i32>` cannot be shared between threads safely
                        +   --> src/main.rs:9:18
                        +    |
                        +9   |     let thread = thread::spawn(move|| {
                        +    |                  ^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
                        +    |
                        +    = help: the trait `Sync` is not implemented for `RefCell<i32>`
                        +    = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
                        +    = note: required because it appears within the type `[closure@src/main.rs:9:32: 11:6]`
                        +note: required by a bound in `spawn`
                        +
                        +

                        And that bound mentioned in the last line looks like this:

                        +
                        pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
                        +    F: FnOnce() -> T,
                        +    F: Send + 'static,
                        +    T: Send + 'static,
                        +
                        +

                        Exercise for the reader

                        +

                        Why is it impossible to share a reference to a Mutex between threads spawned with std::thread::spawn?

                        +

                        Data parallelism with Rayon

                        +

                        Rayon is a library for parallelization of data processing. +It can be used to parallelize the execution of functions over a collection of data by switching the standard Iterator to a ParallelIterator. +It works very similar to Java's parallel streams.

                        +

                        Why do that? Because thread synchronization is hard! Rust prevents data races, but logical races and deadlocks are impossible to prevent!!

                        +

                        Rayon's FAQ is worth reading.

                        +

                        Reading

                        + +

                        No assignment this week

                        +

                        Please work on the first iteration of the big project instead.

                        + + +
                        +
                        + + + + +
                        + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/10-design-patterns/index.html b/lessons/10-design-patterns/index.html new file mode 100644 index 0000000..39eb103 --- /dev/null +++ b/lessons/10-design-patterns/index.html @@ -0,0 +1,246 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                        + + +
                        + +
                        + +
                        +
                        +
                          +
                          +
                          + +
                          + +

                          Design patterns

                          +

                          + 2024-11-21 (last edit: 2022-12-05) +

                          +

                          Object-oriented programming and Rust

                          +

                          The book has a chapter dedicated to it. +Especially the "typestate" pattern is very interesting. +You can read more about it here.

                          +

                          How to build a good library

                          +

                          These guidelines have been created by the Rust library team.

                          +

                          How to handle errors

                          +

                          This post is from 2020, but the libraries it mentions (anyhow and thiserror) are still the most popular.

                          +

                          Serde

                          +

                          Serde is the most popular serialization library for Rust.

                          +

                          Assignment

                          +

                          This week's assignment is to write a "distributed" calculator. +You should base your solution on the final project from the book.

                          + + +
                          +
                          + + + + +
                          + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/11-async-1/index.html b/lessons/11-async-1/index.html new file mode 100644 index 0000000..edf8ec1 --- /dev/null +++ b/lessons/11-async-1/index.html @@ -0,0 +1,240 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                          + + +
                          + +
                          + +
                          +
                          +
                            +
                            +
                            + +
                            + +

                            Async: Part 1

                            +

                            + 2024-11-28 (last edit: 2024-11-27) +

                            +

                            Tokio

                            +

                            We'll use the Tokio tutorial (chapters Overview-Channels).

                            +

                            Common Rust Lifetime Misconceptions

                            +

                            Please read this blogpost.

                            +

                            Assignment 6 (graded)

                            +

                            Calculator

                            +

                            Deadline: 04.12.2024 23:59

                            + + +
                            +
                            + + + + +
                            + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/12-project-feedback/index.html b/lessons/12-project-feedback/index.html new file mode 100644 index 0000000..6feaa23 --- /dev/null +++ b/lessons/12-project-feedback/index.html @@ -0,0 +1,396 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                            + + +
                            + +
                            + +
                            +
                            +
                              +
                              +
                              + +
                              + +

                              Project feedback

                              +

                              + 2022-12-29 (last edit: 2022-12-29) +

                              +

                              Project feedback

                              +

                              Unwrapping options/results

                              +

                              Always ask yourself twice if you really need to unwrap. In most cases, you don't have to. Use pattern matching instead, +as it provides a static guarantee that the value is present.

                              +

                              Pattern matching prevents you from writing code like this:

                              +
                              fn main() {
                              +    let x: Option<i32> = some_function();
                              +
                              +    if x.is_some() {
                              +        println!("x is {}", x.unwrap());
                              +    }
                              +
                              +    // Let's say this line was added later and/or you forgot to put it in the if statement.
                              +    do_something(x.unwrap()); // this will blow up if x == None!
                              +}
                              +
                              +

                              Instead, you can write:

                              +
                              fn main() {
                              +    let x: Option<i32> = some_function();
                              +
                              +    if let Some(x) = x {
                              +        println!("x is {}", x);
                              +        do_something(x);
                              +    }
                              +}
                              +
                              +

                              Question mark operator

                              +

                              In methods that return Result or Option, you can use the question mark operator to return early if the value is None or Err. +See: https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html

                              +

                              Logging

                              +

                              You can use the log crate to log messages. It's better than println! because it +can be easily turned off. It also allows you to use different severity levels (e.g. info, warn, error) and only +log messages above a certain level.

                              +

                              &String vs &str

                              +

                              See https://doc.rust-lang.org/book/ch04-03-slices.html#string-slices-as-parameters +In general, if you want to pass a reference to a string, use &str instead of &String.

                              +

                              Use current versions of dependencies

                              +

                              You can use cargo upgrades to check for outdated dependencies.

                              +

                              If your project has separate binaries, use multiple binaries or a workspace

                              +

                              You can have multiple binaries in a single cargo project. Simply place them in the src/bin directory. +You can run them with cargo run --bin <name>. Alternatively, you can setup a +workspace.

                              +

                              Run clippy & cargo fmt

                              +

                              This should have become a habit by now. You can disable clippy warnings for a single item with #[allow(clippy::...)], +but in most cases you shouldn't do that.

                              +

                              If you need to escape characters in a string, use raw strings

                              +

                              See https://doc.rust-lang.org/reference/tokens.html#raw-string-literals

                              +

                              How to handle errors?

                              +

                              Short: https://kerkour.com/rust-error-handling

                              +

                              Long: https://www.lpalmieri.com/posts/error-handling-rust/

                              +

                              Don't pass around locked mutex's contents

                              +

                              If you have a mutex, you can use lock() to get a guard that will unlock the mutex when it goes out of scope. +But don't pass the contents of the guard to functions that can block (unless the mutex must be locked for +the entire duration of the function). +Instead of:

                              +
                              use std::sync::Mutex;
                              +use std::thread;
                              +use std::time::Duration;
                              +use std::time::Instant;
                              +
                              +fn handle_function(counter: &mut i32) {
                              +    thread::sleep(Duration::from_secs(1));
                              +    *counter += 1;
                              +    thread::sleep(Duration::from_secs(1));
                              +}
                              +
                              +fn main() {
                              +    let counter = Mutex::new(1);
                              +
                              +    thread::scope(|s| {
                              +        for i in 0..10 {
                              +            let counter = &counter;
                              +            s.spawn(move || {
                              +                println!("Thread {i} started");
                              +                let now = Instant::now();
                              +                let mut counter = counter.lock().unwrap();
                              +                handle_function(&mut counter); // lock is held for 2 seconds
                              +                println!("Thread {i} finished after {}s", now.elapsed().as_secs());
                              +            });
                              +        }
                              +    })
                              +}
                              +
                              +

                              You should do this:

                              +
                              use std::sync::Mutex;
                              +use std::thread;
                              +use std::time::Duration;
                              +use std::time::Instant;
                              +
                              +fn handle_function(counter: &Mutex<i32>) { // <-- changed
                              +    thread::sleep(Duration::from_secs(1));
                              +    {
                              +        let mut counter = counter.lock().unwrap(); // <-- changed
                              +        *counter += 1;
                              +        // lock is held only for the duration of the block
                              +        // it is important to create a new scope here, otherwise the lock would be held for another second
                              +    }
                              +    thread::sleep(Duration::from_secs(1));
                              +}
                              +
                              +fn main() {
                              +    let counter = Mutex::new(1);
                              +
                              +    thread::scope(|s| {
                              +        for i in 0..10 {
                              +            let counter = &counter;
                              +            s.spawn(move || {
                              +                println!("Thread {i} started");
                              +                let now = Instant::now();
                              +                handle_function(counter); // <-- changed! we don't lock here
                              +                println!("Thread {i} finished after {}s", now.elapsed().as_secs());
                              +            });
                              +        }
                              +    })
                              +}
                              +
                              +
                              +

                              Compare the output of the two programs. The first one will take 20 seconds to finish, while the second one will take 2 seconds.

                              +

                              First one:

                              +
                              Thread 1 started
                              +Thread 0 started
                              +Thread 2 started
                              +Thread 3 started
                              +Thread 4 started
                              +Thread 5 started
                              +Thread 6 started
                              +Thread 7 started
                              +Thread 8 started
                              +Thread 9 started
                              +Thread 1 finished after 2s
                              +Thread 0 finished after 4s
                              +Thread 2 finished after 6s
                              +Thread 3 finished after 8s
                              +Thread 4 finished after 10s
                              +Thread 5 finished after 12s
                              +Thread 6 finished after 14s
                              +Thread 7 finished after 16s
                              +Thread 8 finished after 18s
                              +Thread 9 finished after 20s
                              +
                              +
                              +

                              Second one:

                              +
                              Thread 0 started
                              +Thread 2 started
                              +Thread 1 started
                              +Thread 3 started
                              +Thread 4 started
                              +Thread 5 started
                              +Thread 6 started
                              +Thread 7 started
                              +Thread 8 started
                              +Thread 9 started
                              +Thread 1 finished after 2s
                              +Thread 2 finished after 2s
                              +Thread 0 finished after 2s
                              +Thread 3 finished after 2s
                              +Thread 4 finished after 2s
                              +Thread 5 finished after 2s
                              +Thread 6 finished after 2s
                              +Thread 7 finished after 2s
                              +Thread 8 finished after 2s
                              +Thread 9 finished after 2s
                              +
                              + + +
                              +
                              + + + + +
                              + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/13-async-2/index.html b/lessons/13-async-2/index.html new file mode 100644 index 0000000..d26f921 --- /dev/null +++ b/lessons/13-async-2/index.html @@ -0,0 +1,388 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                              + + +
                              + +
                              + +
                              +
                              +
                                +
                                +
                                + +
                                + +

                                Async: Part 2

                                +

                                + 2024-12-05 (last edit: 2022-05-23) +

                                +

                                Reinventing futures

                                +

                                We recently got our feet wet with the async/await functionality of Rust by using the Tokio library. With this basic understanding of what we expect out of futures, let's try to come up with their details ourselves.

                                +

                                We know that, when asked, a future can either give us a ready value or still be waiting for it. Asking about the future's result is called polling. Our future could look something like this:

                                +
                                trait SimpleFuture {
                                +    type Output;
                                +    fn poll(&mut self) -> Poll<Self::Output>;
                                +}
                                +
                                +enum Poll<T> {
                                +    Ready(T),
                                +    Pending,
                                +}
                                +
                                +

                                The poll method can be called to check for the result of the future. There is a flaw in this however - whatever is coordinating our future-based computations will have to constantly poll each of them in hope they are ready to do some work.

                                +
                                trait SimpleFuture {
                                +    type Output;
                                +    fn poll(&mut self, wake: fn()) -> Poll<Self::Output>;
                                +}
                                +
                                +
                                +

                                We can solve this by attaching a callback to our polling. The wake function passed to poll can be used to notify whoever issued the poll that the future is ready to make some progress and should be polled.

                                +

                                Let's picture a quick example of how our SimpleFuture could be used.

                                +
                                pub struct SocketRead<'a> {
                                +    socket: &'a Socket,
                                +}
                                +
                                +impl SimpleFuture for SocketRead<'_> {
                                +    type Output = Vec<u8>;
                                +
                                +    fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
                                +        if self.socket.has_data_to_read() {
                                +            // The socket has data -- read it into a buffer and return it.
                                +            Poll::Ready(self.socket.read_buf())
                                +        } else {
                                +            // The socket does not yet have data.
                                +            //
                                +            // Arrange for `wake` to be called once data is available.
                                +            // When data becomes available, `wake` will be called, and the
                                +            // user of this `Future` will know to call `poll` again and
                                +            // receive data.
                                +            self.socket.set_readable_callback(wake);
                                +            Poll::Pending
                                +        }
                                +    }
                                +}
                                +
                                +

                                Combining futures

                                +

                                With the SimpleFuture at our disposal we can easily model more advanced concurrent computations.

                                +
                                /// Concurrency is achieved via the fact that calls to `poll` each future
                                +/// may be interleaved, allowing each future to advance itself at its own pace.
                                +pub struct Join<FutureA, FutureB> {
                                +    // Each field may contain a future that should be run to completion.
                                +    // If the future has already completed, the field is set to `None`.
                                +    // This prevents us from polling a future after it has completed, which
                                +    // would violate the contract of the `Future` trait.
                                +    a: Option<FutureA>,
                                +    b: Option<FutureB>,
                                +}
                                +
                                +impl<FutureA, FutureB> SimpleFuture for Join<FutureA, FutureB>
                                +where
                                +    FutureA: SimpleFuture<Output = ()>,
                                +    FutureB: SimpleFuture<Output = ()>,
                                +{
                                +    type Output = ();
                                +    fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
                                +        // Attempt to complete future `a`.
                                +        if let Some(a) = &mut self.a {
                                +            if let Poll::Ready(()) = a.poll(wake) {
                                +                self.a.take();
                                +            }
                                +        }
                                +
                                +        // Attempt to complete future `b`.
                                +        if let Some(b) = &mut self.b {
                                +            if let Poll::Ready(()) = b.poll(wake) {
                                +                self.b.take();
                                +            }
                                +        }
                                +
                                +        if self.a.is_none() && self.b.is_none() {
                                +            // Both futures have completed -- we can return successfully
                                +            Poll::Ready(())
                                +        } else {
                                +            // One or both futures returned `Poll::Pending` and still have
                                +            // work to do. They will call `wake()` when progress can be made.
                                +            Poll::Pending
                                +        }
                                +    }
                                +}
                                +
                                +

                                We can also queue futures like this:

                                +
                                pub struct AndThenFut<FutureA, FutureB> {
                                +    first: Option<FutureA>,
                                +    second: FutureB,
                                +}
                                +
                                +impl<FutureA, FutureB> SimpleFuture for AndThenFut<FutureA, FutureB>
                                +where
                                +    FutureA: SimpleFuture<Output = ()>,
                                +    FutureB: SimpleFuture<Output = ()>,
                                +{
                                +    type Output = ();
                                +    fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
                                +        if let Some(first) = &mut self.first {
                                +            match first.poll(wake) {
                                +                // We've completed the first future -- remove it and start on
                                +                // the second!
                                +                Poll::Ready(()) => self.first.take(),
                                +                // We couldn't yet complete the first future.
                                +                Poll::Pending => return Poll::Pending,
                                +            };
                                +        }
                                +        // Now that the first future is done, attempt to complete the second.
                                +        self.second.poll(wake)
                                +    }
                                +}
                                +
                                +

                                Exercise

                                +

                                The last example assumes that both futures are already constructed. In practice, however, we often want to chain futures that use the results of their predecessors, like this - get_breakfast().and_then(|food| eat(food));. Try implementing this behavior by adding a new method to the SimpleFuture trait called and_then and something that models this sequential computation (like the previous AndThenFut future).

                                +

                                The real deal

                                +

                                We weren't far from the actual way Rust's futures are structured. The Future trait looks as follows:

                                +
                                trait Future {
                                +    type Output;
                                +    fn poll(
                                +        // Note the change from `&mut self` to `Pin<&mut Self>`:
                                +        self: Pin<&mut Self>,
                                +        // and the change from `wake: fn()` to `cx: &mut Context<'_>`:
                                +        cx: &mut Context<'_>,
                                +    ) -> Poll<Self::Output>;
                                +}
                                +
                                +

                                There are two differences here. Firstly, we use a context instead of a standalone wake method. Since this callback was just a simple function pointer, there was no way for it to hold any data pertaining to which future called it. +Secondly, we take self as a Pin<>. This enables us to create immovable futures - we will go into it later.

                                +

                                Coordinating futures - waker & executor

                                +

                                Using wakers and context

                                +

                                We will follow the steps in the book to make a future that runs a separate thread that sleeps for a given duration and only then returns a result.

                                +

                                Executor

                                +

                                We will follow the steps in the book to create our own executor to run our futures on.

                                +

                                Obligatory reading

                                + +

                                Additional reading

                                + +

                                Assignment 7 (graded)

                                +

                                Calculator

                                +

                                Deadline: 18.12.2024 23:59

                                + + +
                                +
                                + + + + +
                                + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/14-macros/index.html b/lessons/14-macros/index.html new file mode 100644 index 0000000..a3d1702 --- /dev/null +++ b/lessons/14-macros/index.html @@ -0,0 +1,245 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + +
                                + + +
                                + +
                                + +
                                +
                                +
                                  +
                                  +
                                  + +
                                  + +

                                  Macros

                                  +

                                  + 2024-12-12 (last edit: 2022-06-07) +

                                  +

                                  Reading

                                  + + + +
                                  +
                                  + + + + +
                                  + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/index.html b/lessons/index.html new file mode 100644 index 0000000..c0f6355 --- /dev/null +++ b/lessons/index.html @@ -0,0 +1,328 @@ + + + + + + + + Rust course + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lessons/old/2021L/00-organizational/index.html b/lessons/old/2021L/00-organizational/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/00-organizational/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/01-introduction/clippy.jpg b/lessons/old/2021L/01-introduction/clippy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cf490ba9e1f9daaabae3f8edf2b01b1f7a7d97e1 GIT binary patch literal 27148 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 literal 0 HcmV?d00001 diff --git a/lessons/old/2021L/01-introduction/conditionals.rs b/lessons/old/2021L/01-introduction/conditionals.rs new file mode 100644 index 0000000..441aba6 --- /dev/null +++ b/lessons/old/2021L/01-introduction/conditionals.rs @@ -0,0 +1,20 @@ +#![allow(unused_variables)] + +fn main() { + let x = 42; + + if x == 42 { + println!("x is 42"); + } else if x == 43 { + println!("x is 43"); + } else { + println!("x is not 42 or 43"); + } + + // we can also use ifs as expressions + let a_or_b = if x == 0 { + "a" // notice no semicolon at the end + } else { + "b" + }; +} diff --git a/lessons/old/2021L/01-introduction/errors_demo.c b/lessons/old/2021L/01-introduction/errors_demo.c new file mode 100644 index 0000000..936ac9c --- /dev/null +++ b/lessons/old/2021L/01-introduction/errors_demo.c @@ -0,0 +1,35 @@ +#include + +#define LENGTH 3 + +int main() { + //# Syntax error + // printf("hello world"; + + //char* array[LENGTH] = {"hello", "ancient", "world!"}; + + //# Array out-of-bounds with a statically known index + // printf("%s\n", array[LENGTH]); + + //# Array out-of-bounds with a dynamically computed index + // for (int i = 0; i <= LENGTH; i++) { + // printf("%s\n", array[i]); + // } + + //# Doing God knows what + // char* format = "a very innocent hello %s"; + // printf(format); + + //# Division by zero + // int joy_division = 1/0; + + // int joy = 0; + // int joy_division = 1/joy; + + // int joy = 0 ? 1 : 0; + // int joy_division = 1/joy; + + // printf("joy division equals %d", joy_division); + + return 0; +} diff --git a/lessons/old/2021L/01-introduction/errors_demo.cpp b/lessons/old/2021L/01-introduction/errors_demo.cpp new file mode 100644 index 0000000..1c7d88b --- /dev/null +++ b/lessons/old/2021L/01-introduction/errors_demo.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +using std::cout; +using std::endl; + +int main() { + //# Syntax error + // cout < "hello world"; + + // constexpr int length = 3; + // std::array array = {"hello", "old", "world!"}; + + //# Array access with an out of bounds index and bounds checking during compile time + // cout << std::get(array) << endl; + + //# Array access with an out of bounds index and bounds checking during runtime + // cout << array.at(length) << endl; + + //# Most common access without any checks + // cout << array[length] << endl; + + //# Array out-of-bounds with a dynamically computed index + // for (int i = 0; i <= length; i++) { + // cout << array.at(i) << endl; + // } + + //# This will be there in Clang 14 ... + // std::string format = std::format("a very innocent hello {}"); + // cout << format << endl; + + //# ... but for now, this is doing God knows what + // const char* format = "a very innocent hello %s"; + // printf(format); + + //# Division by zero + // int joy_division = 1/0; + + // int joy = 0; + // int joy_division = 1/joy; + + // int joy = false ? 1 : 0; + // int joy_division = 1/joy; + + // cout << "joy division equals " << joy_division << endl; + + return 0; +} diff --git a/lessons/old/2021L/01-introduction/errors_demo.rs b/lessons/old/2021L/01-introduction/errors_demo.rs new file mode 100644 index 0000000..bf5a394 --- /dev/null +++ b/lessons/old/2021L/01-introduction/errors_demo.rs @@ -0,0 +1,29 @@ +fn main() { + //# Syntax error + // println("hello world"); + + // let array = ["hello", "new", "world!"]; + + //# Array out-of-bounds with a statically known index + // println!("{}", array[3]); + + //# Array out-of-bounds with a dynamically computed index + // for i in 0..=array.len() { + // println!("{}", array[i]); + // } + + //# An unsuccessful attempt at emulating C++'s ability to read the memory we're not supposed to access + // let format = "a very innocent hello {}"; + // println!(format); + + //# Division by zero + // let joy_division = 0/0; + + // let joy = 0; + // let joy_division = 0/joy; + + // let joy = if false {1} else {0}; + // let joy_division = 0/joy; + + // println!("{}", joy_division); +} diff --git a/lessons/old/2021L/01-introduction/functions.rs b/lessons/old/2021L/01-introduction/functions.rs new file mode 100644 index 0000000..2987a36 --- /dev/null +++ b/lessons/old/2021L/01-introduction/functions.rs @@ -0,0 +1,12 @@ +fn get_5() -> u32 { + 5 // we could also write "return 5;" +} + +fn print_sum(a: u32, b: u32) { + println!("a + b = {}", a + b); +} + +fn main() { + let a = 100; + print_sum(a, get_5()); +} diff --git a/lessons/old/2021L/01-introduction/hello_world.rs b/lessons/old/2021L/01-introduction/hello_world.rs new file mode 100644 index 0000000..fa9fb84 --- /dev/null +++ b/lessons/old/2021L/01-introduction/hello_world.rs @@ -0,0 +1,4 @@ +fn main() { + let name = "World"; + println!("Hello, {}!", name); // using the println! macro +} diff --git a/lessons/old/2021L/01-introduction/index.html b/lessons/old/2021L/01-introduction/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/01-introduction/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/01-introduction/loops.rs b/lessons/old/2021L/01-introduction/loops.rs new file mode 100644 index 0000000..8a02d72 --- /dev/null +++ b/lessons/old/2021L/01-introduction/loops.rs @@ -0,0 +1,55 @@ +#![allow(unused_variables)] + +fn main() { + for i in 0..10 { + println!("i is {}", i); // i in [0, 10) + } + + let mut x = 0; + + while x < 50 { + x += 1; + } + + let mut y = 0; + let mut iterations = 0; + loop { + iterations += 1; + if iterations % 2 == 0 { + continue; + } + y += 1; + if y == 10 { + break; + } + } + + // we can use labels to refer to a specific loop + let mut count = 0; + 'counting_up: loop { + let mut remaining = 10; + + loop { + if remaining == 9 { + break; + } + if count == 2 { + break 'counting_up; // ends the outer loop + } + remaining -= 1; + } + + count += 1; + } + + // We can use break with a value. + // Because loops are expressions too, + // the value we break with will be returned from the functions + let mut counter = 0; + let value = loop { + counter += 1; + if counter == 10 { + break 32; + } + }; +} diff --git a/lessons/old/2021L/01-introduction/variables.rs b/lessons/old/2021L/01-introduction/variables.rs new file mode 100644 index 0000000..3350568 --- /dev/null +++ b/lessons/old/2021L/01-introduction/variables.rs @@ -0,0 +1,18 @@ +#![allow(unused_variables)] +#![allow(unused_assignments)] + +fn main() { + let x = 40; // inferred type + let y: i32 = 100; // specified type + + { + let x = 40 + 2; // shadowing + println!("x is {}", x); // prints 42 + } + + // x = 0; // compilation error, variables are by default immutable + let mut x = 40; // declare as mutable + x = 0; // now we can reassign + + x += 1; // x = x + 1 +} diff --git a/lessons/old/2021L/02-ownership/index.html b/lessons/old/2021L/02-ownership/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/02-ownership/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/03-data-types/data_types.rs b/lessons/old/2021L/03-data-types/data_types.rs new file mode 100644 index 0000000..78cd053 --- /dev/null +++ b/lessons/old/2021L/03-data-types/data_types.rs @@ -0,0 +1,82 @@ +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct Position(i32, i32); // tuple struct + +// Could Hero derive the Copy trait? +#[derive(Clone, Debug, Eq, PartialEq)] +struct Hero { + name: String, + level: u32, + experience: u32, + position: Position, +} + +// we can add methods to structs using the 'impl' keyword +impl Hero { + // static method + fn new(name: String) -> Hero { + Hero { + name, + level: 1, + experience: 0, + position: Position(0, 0), + } + } +} + +// multiple impl blocks are possible for one struct +impl Hero { + // instance method, first argument (self) is the calling instance + fn distance(&self, pos: Position) -> u32 { + // fields of tuples and tuple structs can be accessed through 'tuple.[i]' + (pos.0 - self.position.0).unsigned_abs() + (pos.1 - self.position.1).unsigned_abs() + } + + // mutable borrow of self allows to change instance fields + fn level_up(&mut self) { + self.experience = 0; + self.level += 1; + } + + // 'self' is not borrowed here and will be moved into the method + fn die(self) { + println!( + "Here lies {}, a hero who reached level {}. RIP.", + self.name, self.level + ); + } +} + +fn main() { + let mut hero: Hero = Hero::new(String::from("Marty The Brave")); + hero.level_up(); // 'self' is always passed implicitly + + // fields other than 'name' will be the same as in 'hero' + let steve = Hero { + name: String::from("Steve The Normal Guy"), + ..hero + }; + + assert_eq!(hero.level, steve.level); + + let mut twin = hero.clone(); + + // we can compare Hero objects because it derives the PartialEq trait + assert_eq!(hero, twin); + twin.level_up(); + assert_ne!(hero, twin); + hero.level_up(); + assert_eq!(hero, twin); + + // we can print out a the struct's debug string with '{:?}' + println!("print to stdout: {:?}", hero); + + hero.die(); // 'hero' is not usable after this invocation, see the method's definiton + + // the dbg! macro prints debug strings to stderr along with file and line number + dbg!("print to stderr: {}", twin); + + let pos = Position(42, 0); + let dist = steve.distance(pos); // no clone here as Position derives the Copy trait + println!("{:?}", pos); + assert_eq!(dist, 42); +} diff --git a/lessons/old/2021L/03-data-types/index.html b/lessons/old/2021L/03-data-types/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/03-data-types/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/04-enums/enums.c b/lessons/old/2021L/04-enums/enums.c new file mode 100644 index 0000000..9e60c40 --- /dev/null +++ b/lessons/old/2021L/04-enums/enums.c @@ -0,0 +1,29 @@ +#include + +enum shirt_size { + small, + medium, + large, + xlarge +}; + +void print_size(enum shirt_size size) { + printf("my size is "); + if (size == small) { + printf("small"); + } else if (size == medium) { + printf("medium"); + } else if (size == large) { + printf("large"); + } else if (size == xlarge) { + printf("xlarge"); + } else { + printf("unknown"); + } + printf("\n"); +} + +int main() { + enum shirt_size my_size = medium; + print_size(my_size); +} diff --git a/lessons/old/2021L/04-enums/enums.rs b/lessons/old/2021L/04-enums/enums.rs new file mode 100644 index 0000000..ceab783 --- /dev/null +++ b/lessons/old/2021L/04-enums/enums.rs @@ -0,0 +1,28 @@ +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(dead_code)] + +#[derive(Debug)] +enum NamedSize { + Small, + Medium, + Large, + XL, +} + +#[derive(Debug)] +enum ShirtSize { + Named(NamedSize), + Numeric(u32), +} + +fn main() { + println!( + "Isn't it strange that some clothes' sizes are adjectives like {:?},", + ShirtSize::Named(NamedSize::Small) + ); + println!( + "but sometimes they are numbers like {:?}?", + ShirtSize::Numeric(42) + ); +} diff --git a/lessons/old/2021L/04-enums/index.html b/lessons/old/2021L/04-enums/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/04-enums/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/04-enums/option.rs b/lessons/old/2021L/04-enums/option.rs new file mode 100644 index 0000000..3c73877 --- /dev/null +++ b/lessons/old/2021L/04-enums/option.rs @@ -0,0 +1,112 @@ +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn main() { + let mut not_null: i32 = 42; + not_null = 43; + // not_null = None; // this won't compile because it's a different type! + + let mut nullable: Option = Some(42); + nullable = None; + nullable = Some(43); + + // such construction is rare, but possible + let mut double_nullable: Option> = Some(Some(42)); + // assert_ne!(double_nullable, Some(42)); // this won't even compile because it's a different type! + double_nullable = None; + double_nullable = Some(None); + + // None and Some(None) are different! + assert_ne!(double_nullable, None); + + // Now recall that division by 0 *panics* + // A panic is an unrecoverable error + // It is not an exception! + // And in Rust there are no exceptions, so there are no try/catch blocks + // Now let's imagine that we want to divide one number by another + fn divide(dividend: i32, divisor: i32) -> i32 { + dividend / divisor + } + + // We get the divisor from the user, so it can be 0 + // We want to handle this situation gracefully - we don't want to crash the program! + // We can do this by using the Option type + fn safe_divide(dividend: i32, divisor: i32) -> Option { + if divisor == 0 { + None + } else { + Some(dividend / divisor) + } + } + + // Fortunately, such a function is already included in the standard library + let number: i32 = 42; + // We need to specify the type explicitly + // because checked_div is implemented for all integer types + // and Rust won't know which type we want to use + assert_eq!(number.checked_div(2), Some(21)); + assert_eq!(number.checked_div(0), None); + + // Now let's imagine we search for a value in a vector + let numbers = vec![1, 2, 3, 4, 5]; + let three = numbers.iter().copied().find(|&x| x == 3); + assert_eq!(three, Some(3)); + let seven = numbers.iter().copied().find(|&x| x == 7); + assert_eq!(seven, None); + // We won't delve deeper into the details of how iterators work for now, + // but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust + + // Usually there are two kinds of methods: + // ones that will panic if the argument is incorrect, + // numbers[8]; // this will panic! + // and `checked` ones that return an Option + assert_eq!(numbers.get(8), None); + + // We can use `unwrap` to get the value out of an Option + // but we must be absolutely sure that the Option is Some, otherwise we'll get a panic + // numbers.get(8).unwrap(); // this will panic! + assert_eq!(numbers.get(8).copied().unwrap_or(0), 0); // or we can provide a default value + + // Usually instead of unwrapping we use pattern matching, we'll get to this in a minute + // but first let's see what else we can do with an option + let number: Option = Some(42); + // We can use `map` to transform the value inside an Option + let doubled = number.map(|x| x * 2); + assert_eq!(doubled, Some(84)); + // We can use flatten to reduce one level of nesting + let nested = Some(Some(42)); + assert_eq!(nested.flatten(), Some(42)); + // We can use `and_then` to chain multiple options + // This operation is called `flatmap` in some languages + let chained = number + .and_then(|x| x.checked_div(0)) + .and_then(|x| x.checked_div(2)); + assert_eq!(chained, None); + + // The last two things we'll cover here are `take` and `replace` + // They are important when dealing with non-Copy types + // `take` will return the value inside an Option and leave a None in its place + let mut option: Option = None; + // Again, we need to specify the type + // Even though we want to say that there is no value inside the Option, + // this absent value must have a concrete type! + assert_eq!(option.take(), None); + assert_eq!(option, None); + + let mut x = Some(2); + let y = x.take(); + assert_eq!(x, None); + assert_eq!(y, Some(2)); + + // `replace` can be used to swap the value inside an Option + let mut x = Some(2); + let old = x.replace(5); + assert_eq!(x, Some(5)); + assert_eq!(old, Some(2)); + + let mut x = None; + let old = x.replace(3); + assert_eq!(x, Some(3)); + assert_eq!(old, None); +} diff --git a/lessons/old/2021L/04-enums/pattern_matching.rs b/lessons/old/2021L/04-enums/pattern_matching.rs new file mode 100644 index 0000000..215a74a --- /dev/null +++ b/lessons/old/2021L/04-enums/pattern_matching.rs @@ -0,0 +1,128 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +fn main() { + // Pattern matching is basically a switch on steroids. + let number = rand::random::(); + match number % 7 { + 0 => println!("{number} is divisible by 7"), + 1 => println!("{number} is *almost* divisible by 7"), + _ => println!("{number} is not divisible by 7"), + } + + #[derive(Debug)] + enum Color { + Pink, + Brown, + Lime, + } + + let color = Color::Lime; + match color { + Color::Pink => println!("My favorite color!"), + _ => println!("Not my favorite color!"), // _ is a wildcard + // Rust will statically check that we covered all cases or included a default case. + } + + // We can also use pattern matching to match on multiple values. + match (color, number % 7) { + (Color::Pink, 0) => println!("My favorite color and number!"), + (Color::Pink, _) => println!("My favorite color!"), + (_, 0) => println!("My favorite number!"), + (_, _) => println!("Not my favorite color or number!"), + } + // (This is not special syntax, we're just pattern matching tuples.) + + // But we can also *destructure* the value + struct Human { + age: u8, + favorite_color: Color, + } + + let john = Human { + age: 42, + favorite_color: Color::Pink, + }; + + match &john { + Human { + age: 42, + favorite_color: Color::Pink, + } => println!("Okay, that's John!"), + Human { + favorite_color: Color::Pink, + .. + } => println!("Not John, but still his favorite color!"), + _ => println!("Somebody else?"), + } + + // Note two things: + // 1. Color is *not* Eq, so we can't use == to compare it, but pattern matching is fine. + // 2. We *borrowed* the value, so we can use it after the match. + + println!("John is {} years old and still kicking!", john.age); + + // To save some time, we can use `if let` to match against only one thing + // We could also use `while let ... {}` in the same way + if let Color::Pink = &john.favorite_color { + println!("He's also a man of great taste"); + } + + // We can match ranges... + match john.age { + 0..=12 => println!("John is a kid!"), + 13..=19 => println!("John is a teenager!"), + 20..=29 => println!("John is a young adult!"), + 30..=49 => println!("John is an adult!"), + 50..=69 => println!("John is mature!"), + _ => println!("John is old!"), + } + + // We can use match and capture the value at the same time. + match john.age { + age @ 0..=12 => println!("John is a kid, age {}", age), + age @ 13..=19 => println!("John is a teenager, age {}", age), + age @ 20..=29 => println!("John is a young adult, age {}", age), + age @ 30..=49 => println!("John is an adult, age {}", age), + age @ 50..=69 => println!("John is mature, age {}", age), + age => println!("John is old, age {}", age), + } + + // We can use guards to check for multiple conditions. + match john.age { + age @ 12..=19 if age % 2 == 1 => println!("John is an *odd* teenager, age {}", age), + age if age % 2 == 0 => println!("John is an *even* man, age {}", age), + _ => println!("John is normal"), + } + + // Finally, let's look at some references now + let reference: &i32 = &4; + + match reference { + &val => println!("Value under reference is: {}", val), + } + + // `ref` can be used to create a reference when destructuring + let Human { + age, + ref favorite_color, + } = john; + // `john` is still valid, because we borrowed using `ref` + if let Color::Pink = &john.favorite_color { + println!("John still has his color - {:?}!", favorite_color); + } + + let mut john = john; + + // `ref mut` borrows mutably + let Human { + age, + ref mut favorite_color, + } = john; + // We use `*` to dereference + *favorite_color = Color::Brown; + println!( + "Tastes do change with time and John likes {:?} now.", + john.favorite_color + ); +} diff --git a/lessons/old/2021L/04-enums/result.rs b/lessons/old/2021L/04-enums/result.rs new file mode 100644 index 0000000..ffd0797 --- /dev/null +++ b/lessons/old/2021L/04-enums/result.rs @@ -0,0 +1,56 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +use std::fs::File; +use std::io; +use std::io::Read; + +// Let's try reading from a file. +// Obviously this can fail. +fn first_try() -> io::Result { + let file = File::open("/dev/random"); + match file { + Ok(mut file) => { + // We got a file! + let mut buffer = vec![0; 128]; + // Matching each result quickly become tedious... + match file.read_exact(&mut buffer) { + Ok(_) => { + let gibberish = String::from_utf8_lossy(&buffer); + Ok(gibberish.to_string()) + } + Err(error) => Err(error), + } + } + Err(error) => { + Err(error) // This is needed in order to change the type from `io::Result` to `io::Result<()>` + } + } +} + +// The '?' operator allows us to return early in case of an error +// (it automatically converts the error type) +fn second_try(filename: &'static str) -> io::Result { + let mut file = File::open(filename)?; + let mut buffer = vec![0; 128]; + file.read_exact(&mut buffer)?; + let gibberish = String::from_utf8_lossy(&buffer); + Ok(gibberish.to_string()) +} + +fn main() { + let filenames = [ + "/dev/random", + "/dev/null", + "/dev/cpu", + "/dev/fuse", + "there_certainly_is_no_such_file", + ]; + for filename in filenames { + println!("Trying to read from '{}'", filename); + match second_try(filename) { + Ok(gibberish) => println!("{}", gibberish), + Err(error) => println!("Error: {}", error), + } + } +} diff --git a/lessons/old/2021L/04-enums/tagged_union.cpp b/lessons/old/2021L/04-enums/tagged_union.cpp new file mode 100644 index 0000000..ae07b6e --- /dev/null +++ b/lessons/old/2021L/04-enums/tagged_union.cpp @@ -0,0 +1,35 @@ +#include + +// Taken from: https://en.cppreference.com/w/cpp/language/union + +// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), +// and three variant members (c, i, d) +struct S +{ + enum{CHAR, INT, DOUBLE} tag; + union + { + char c; + int i; + double d; + }; +}; + +void print_s(const S& s) +{ + switch(s.tag) + { + case S::CHAR: std::cout << s.c << '\n'; break; + case S::INT: std::cout << s.i << '\n'; break; + case S::DOUBLE: std::cout << s.d << '\n'; break; + } +} + +int main() +{ + S s = {S::CHAR, 'a'}; + print_s(s); + s.tag = S::INT; + s.i = 123; + print_s(s); +} diff --git a/lessons/old/2021L/05-tests/index.html b/lessons/old/2021L/05-tests/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/05-tests/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/05-tests/test.rs b/lessons/old/2021L/05-tests/test.rs new file mode 100644 index 0000000..e78bb7f --- /dev/null +++ b/lessons/old/2021L/05-tests/test.rs @@ -0,0 +1,30 @@ +// This function is going to be used only in the tests, so we add the `#[cfg(test)]` attribute. +// It means that it won't be compiled in the final executable. +#[cfg(test)] +fn return_42() -> i32 { + 42 +} + +fn frobnicate(x: i32) -> i32 { + println!("frobicating...!"); + x + 40 +} + +fn main() { + frobnicate(2); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + assert_eq!(return_42(), 42); + } + + #[test] + fn test_frobnicate() { + assert_eq!(frobnicate(2), 42); + } +} diff --git a/lessons/old/2021L/06-types-reasoning/basic_trait.rs b/lessons/old/2021L/06-types-reasoning/basic_trait.rs new file mode 100644 index 0000000..1c76202 --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/basic_trait.rs @@ -0,0 +1,38 @@ +#![allow(dead_code)] + +trait Summary { + fn summarize(&self) -> String; +} + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Summary for NewsArticle { + fn summarize(&self) -> String { + format!("{}, by {} ({})", self.headline, self.author, self.location) + } +} + +struct Tweet { + username: String, + content: String, +} + +impl Summary for Tweet { + fn summarize(&self) -> String { + format!("{}: {}", self.username, self.content) + } +} + +fn main() { + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + println!("1 new tweet: {}", tweet.summarize()); +} diff --git a/lessons/old/2021L/06-types-reasoning/generic_largest.rs b/lessons/old/2021L/06-types-reasoning/generic_largest.rs new file mode 100644 index 0000000..7aa6a3b --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/generic_largest.rs @@ -0,0 +1,23 @@ +fn largest(list: &[T]) -> T { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest(&char_list); + println!("The largest char is {}", result); +} diff --git a/lessons/old/2021L/06-types-reasoning/generics.rs b/lessons/old/2021L/06-types-reasoning/generics.rs new file mode 100644 index 0000000..3198df0 --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/generics.rs @@ -0,0 +1,70 @@ +#![allow(dead_code)] + +use std::fmt::Debug; + +// generic enums +enum OurOption { + Some(T), + None, +} + +// generic structs +struct Tuple2 { + x: T, + y: U, +} + +// generic implementation +impl Tuple2 { + fn new(x: T, y: U) -> Self { + Self { x, y } + } +} + +struct Pair { + x: T, + y: T, +} + +// conditional implementation +impl Pair { + fn largest(&self) -> T { + if self.x > self.y { + self.x + } else { + self.y + } + } +} + +// alternative syntax +impl Pair +where + T: PartialOrd + Copy, +{ + fn smallest(&self) -> T { + if self.x < self.y { + self.x + } else { + self.y + } + } +} + +// Here information about the concrete underlying type is erased +// We can only either format or clone the result +fn cloning_machine(item: &(impl Clone + Debug)) -> impl Clone + Debug { + item.clone() +} + +fn main() { + let _opt = OurOption::Some(10); + + let _p1 = Tuple2 { x: 5, y: 10 }; + let _p2 = Tuple2::new(1, 2.5); + + let arr = [1, 2, 3]; + let arr2 = cloning_machine(&arr); + // arr2[0]; // won't compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` + println!("{:?}", arr2) +} diff --git a/lessons/old/2021L/06-types-reasoning/generics_fun.rs b/lessons/old/2021L/06-types-reasoning/generics_fun.rs new file mode 100644 index 0000000..241c389 --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/generics_fun.rs @@ -0,0 +1,35 @@ +use std::fmt::{Display, Formatter}; + +trait DefaultishablyPrintable { + fn defaultish_print() + where + T: Display + Default, + { + println!("{}", T::default()) + } +} + +struct Foo; + +struct Bar; + +impl Display for Bar { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("this is a bar") + } +} + +impl Default for Bar { + fn default() -> Self { + Bar // well, we have no other choice + } +} + +impl DefaultishablyPrintable for Foo {} + +impl DefaultishablyPrintable for Foo {} + +fn main() { + >::defaultish_print(); + >::defaultish_print(); +} diff --git a/lessons/old/2021L/06-types-reasoning/index.html b/lessons/old/2021L/06-types-reasoning/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/06-types-reasoning/lifetimes_basic.rs b/lessons/old/2021L/06-types-reasoning/lifetimes_basic.rs new file mode 100644 index 0000000..a4eaa2b --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/lifetimes_basic.rs @@ -0,0 +1,27 @@ +fn longest<'a>(first: &'a str, second: &'a str) -> &'a str { + if first.len() > second.len() { + first + } else { + second + } +} + +fn main() { + let string1 = String::from("long string is long"); + + { + let string2 = String::from("xyz"); + let result = longest(string1.as_str(), string2.as_str()); + println!("The longest string is {}", result); + } + + // This doesn't compile - incorrect lifetimes + // + // let string1 = String::from("long string is long"); + // let result; + // { + // let string2 = String::from("xyz"); + // result = longest(string1.as_str(), string2.as_str()); + // } + // println!("The longest string is {}", result); +} diff --git a/lessons/old/2021L/06-types-reasoning/lifetimes_elision.rs b/lessons/old/2021L/06-types-reasoning/lifetimes_elision.rs new file mode 100644 index 0000000..9633909 --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/lifetimes_elision.rs @@ -0,0 +1,16 @@ +fn first_two(seq: &[u32]) -> &[u32] { + if seq.len() < 2 { + seq + } else { + &seq[..2] + } +} + +fn main() { + let seq = [1, 2, 3, 4]; + + println!( + "First two elements of the sequence: {:?}", + first_two(&seq[..]) + ); +} diff --git a/lessons/old/2021L/06-types-reasoning/non_generic.rs b/lessons/old/2021L/06-types-reasoning/non_generic.rs new file mode 100644 index 0000000..c983e3b --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/non_generic.rs @@ -0,0 +1,35 @@ +fn largest_i32(list: &[i32]) -> i32 { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn largest_char(list: &[char]) -> char { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest_i32(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest_char(&char_list); + println!("The largest char is {}", result); +} diff --git a/lessons/old/2021L/06-types-reasoning/static_dynamic_dispatch.rs b/lessons/old/2021L/06-types-reasoning/static_dynamic_dispatch.rs new file mode 100644 index 0000000..2d9eeda --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/static_dynamic_dispatch.rs @@ -0,0 +1,47 @@ +trait Speak { + fn speak(&self) -> &'static str; +} + +struct Dog; + +impl Speak for Dog { + fn speak(&self) -> &'static str { + "Hau hau" // it's a Polish dog! + } +} + +struct Human; + +impl Speak for Human { + fn speak(&self) -> &'static str { + "Hello world" + } +} + +// It works like templates in C++ +// A different function will be generated for each T during compilation +// This process is called "monomorphization" +fn static_dispatch(speaking: &T) { + println!("{}!", speaking.speak()); +} + +// Only one copy of that function will exist in the compiled binary +fn dynamic_dispatch(speaking: &dyn Speak) { + println!("{}!", speaking.speak()); +} + +fn main() { + let dog = Dog; + let human = Human; + + static_dispatch(&dog); + static_dispatch(&human); + + dynamic_dispatch(&dog); + dynamic_dispatch(&human); + + // The observable behavior is identical + // Static dispatch in general is a bit faster, + // because there is no need to perform a "vtable lookup". + // But it can also result in bigger binary sizes. +} diff --git a/lessons/old/2021L/06-types-reasoning/trait_default.rs b/lessons/old/2021L/06-types-reasoning/trait_default.rs new file mode 100644 index 0000000..84ba1b3 --- /dev/null +++ b/lessons/old/2021L/06-types-reasoning/trait_default.rs @@ -0,0 +1,67 @@ +#![allow(dead_code)] + +struct Upload { + filename: String, +} + +#[allow(dead_code)] +struct Photo { + filename: String, + width: u32, + height: u32, +} + +trait Description { + fn describe(&self) -> String { + String::from("No description available.") + } +} + +// All default implementations +impl Description for Upload {} + +// Default implementations can be overwritten +impl Description for Photo { + fn describe(&self) -> String { + format!("{} ({} x {})", self.filename, self.width, self.height) + } +} + +// Default implementations can rely on methods with no defaults +trait Size { + fn width(&self) -> u32; + fn height(&self) -> u32; + + fn size(&self) -> u32 { + self.width() * self.height() + } +} + +impl Size for Photo { + fn width(&self) -> u32 { + self.width + } + + fn height(&self) -> u32 { + self.height + } + + // Using default impl of `size()` +} + +fn main() { + let upload = Upload { + filename: String::from("notes.txt"), + }; + + println!("Upload: {}", upload.describe()); + + let photo = Photo { + filename: String::from("stock_crustacean.png"), + width: 100, + height: 150, + }; + + println!("Photo: {}", photo.describe()); + println!("Size: {}", photo.size()); +} diff --git a/lessons/old/2021L/07-feedback/clippy.png b/lessons/old/2021L/07-feedback/clippy.png new file mode 100644 index 0000000000000000000000000000000000000000..9d76971db595f1abe5113f3557b29b92063c56f3 GIT binary patch literal 23592 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 literal 0 HcmV?d00001 diff --git a/lessons/old/2021L/07-feedback/constructor.rs b/lessons/old/2021L/07-feedback/constructor.rs new file mode 100644 index 0000000..a7ec205 --- /dev/null +++ b/lessons/old/2021L/07-feedback/constructor.rs @@ -0,0 +1,34 @@ +mod one { + pub struct Point { + x: i32, + } + + impl Point { + pub fn new(x: i32) -> Point { + Point { x } + } + + pub fn x(&self) -> i32 { + self.x + } + } + + impl Default for Point { + fn default() -> Point { + Point { x: 10 } + } + } +} + +fn main() { + // won't compile, can't initialize private fields + // let p = one::Point { + // x: 1, + // }; + let p = one::Point::new(1); + // won't compile, x is private + // println!("{}", p.x); + println!("{}", p.x()); + let p = one::Point::default(); + println!("{}", p.x()); +} diff --git a/lessons/old/2021L/07-feedback/index.html b/lessons/old/2021L/07-feedback/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/07-feedback/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/07-feedback/number_conversions.rs b/lessons/old/2021L/07-feedback/number_conversions.rs new file mode 100644 index 0000000..9dd324b --- /dev/null +++ b/lessons/old/2021L/07-feedback/number_conversions.rs @@ -0,0 +1,9 @@ +fn main() { + let small_number: u32 = u32::MAX; + // dbg!(small_number + 1); // this will panic (in debug builds, in release build it will wrap) + assert_eq!(small_number as u8, 255); + assert_eq!(small_number as i8, -1); + assert_eq!(small_number as i64, 4294967295); + let converted: Result = small_number.try_into(); + assert!(converted.is_err()); +} diff --git a/lessons/old/2021L/07-feedback/rustfmt.png b/lessons/old/2021L/07-feedback/rustfmt.png new file mode 100644 index 0000000000000000000000000000000000000000..a09e6ff9c883f8350c337917d7b0e41429283045 GIT binary patch literal 18281 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 literal 0 HcmV?d00001 diff --git a/lessons/old/2021L/08-closures-iterators/index.html b/lessons/old/2021L/08-closures-iterators/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/08-closures-iterators/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/09-feedback2/combinators.rs b/lessons/old/2021L/09-feedback2/combinators.rs new file mode 100644 index 0000000..f82b7f7 --- /dev/null +++ b/lessons/old/2021L/09-feedback2/combinators.rs @@ -0,0 +1,37 @@ +fn main() { + let mut res: Result = Ok(5); + + // `map` allows us to transform the value inside `Ok()`, + // while leaving the `Err` untouched + assert_eq!(res.map(|v| v * v), Ok(25)); + + res = Err(5); + assert_eq!(res.map(|v| v * v), Err(5)); + + // With most combinators there are mirrored ones that work on `Err` + // variants instead of `Ok`s. + assert_eq!(res.map_err(|v| v * v), Err(25)); + + // We can swap an `Ok` value for a different one with `and()`. + // Analogously for `Err` and `or()`. + res = Ok(5); + assert_eq!(res.and(Ok(100)), Ok(100)); + + res = Err(5); + assert_eq!(res.and(Ok(100)), Err(5)); + + // `and_then()` and `or_else()` allow us to invoke functions + // only when the result is either an `Ok` or an `Err` respectively. + let sq = |x: i32| -> Result { Ok(x * x) }; + let err = |x: i32| -> Result { Err(x) }; + + assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16)); + assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4)); + assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2)); + assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3)); + + assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2)); + assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2)); + assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9)); + assert_eq!(Err(3).or_else(err).or_else(err), Err(3)); +} \ No newline at end of file diff --git a/lessons/old/2021L/09-feedback2/index.html b/lessons/old/2021L/09-feedback2/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/09-feedback2/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/10-smart-pointers/box.rs b/lessons/old/2021L/10-smart-pointers/box.rs new file mode 100644 index 0000000..9a9f99e --- /dev/null +++ b/lessons/old/2021L/10-smart-pointers/box.rs @@ -0,0 +1,18 @@ +fn box_simple() { + let b = Box::new(5); + println!("b = {}", b); + + let _x = 10 + *b; +} + +// `Box` gives us the indirection required to define +// recursive types +#[allow(dead_code)] +enum List { + Cons(i32, Box), + Nil, +} + +fn main() { + box_simple(); +} diff --git a/lessons/old/2021L/10-smart-pointers/deref_coercion.rs b/lessons/old/2021L/10-smart-pointers/deref_coercion.rs new file mode 100644 index 0000000..c5b14c7 --- /dev/null +++ b/lessons/old/2021L/10-smart-pointers/deref_coercion.rs @@ -0,0 +1,39 @@ +use std::ops::Deref; + +struct MyBox(T); + +// We won't be allocating anything on the heap here as it is not important here. +// We're only focusing on the dereference mechanisms. +impl MyBox { + fn new(x: T) -> MyBox { + MyBox(x) + } +} + +impl Deref for MyBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn hello(name: &str) { + println!("Hello, {}!", name); +} + +fn main() { + let x = 5; + let int_box = MyBox::new(x); + + assert_eq!(5, *int_box); + + // String also implements the `Deref` trait. + // In fact, String actually is a smart pointer. + let s = String::from("I'm a smart pointer too"); + hello(&s); + + // Deref coercion can deal with multiple levels of indirection. + let str_box = MyBox::new(String::from("Rust")); + hello(&str_box); +} diff --git a/lessons/old/2021L/10-smart-pointers/index.html b/lessons/old/2021L/10-smart-pointers/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/10-smart-pointers/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/10-smart-pointers/ref_count.rs b/lessons/old/2021L/10-smart-pointers/ref_count.rs new file mode 100644 index 0000000..0f97932 --- /dev/null +++ b/lessons/old/2021L/10-smart-pointers/ref_count.rs @@ -0,0 +1,31 @@ +use std::rc::Rc; + +struct LoudInt(i32); + +impl Drop for LoudInt { + fn drop(&mut self) { + println!("[{}] Farewell!", self.0); + } +} + +fn main() { + { + let outer_ref; + + { + let inner_ref = Rc::new(LoudInt(5)); + + // strong_count represents the number of owning references pointing + // to data + assert_eq!(Rc::strong_count(&inner_ref), 1); + + outer_ref = Rc::clone(&inner_ref); + + assert_eq!(Rc::strong_count(&inner_ref), Rc::strong_count(&outer_ref)); + assert_eq!(Rc::strong_count(&inner_ref), 2); + } + + println!("The {} still lives!", outer_ref.0); + assert_eq!(Rc::strong_count(&outer_ref), 1); + } +} diff --git a/lessons/old/2021L/10-smart-pointers/weak_ref.rs b/lessons/old/2021L/10-smart-pointers/weak_ref.rs new file mode 100644 index 0000000..b2406f6 --- /dev/null +++ b/lessons/old/2021L/10-smart-pointers/weak_ref.rs @@ -0,0 +1,36 @@ +use std::rc::Rc; + +struct LoudInt(i32); + +impl Drop for LoudInt { + fn drop(&mut self) { + println!("[{}] Farewell!", self.0); + } +} + +fn main() { + let weak_ref; + + { + let shared_ref = Rc::new(LoudInt(5)); + + // weak_count keeps track of the non-owning reference to the data + assert_eq!(Rc::weak_count(&shared_ref), 0); + + // `downgrade()` obtains a weak pointer to Rc's data + weak_ref = Rc::downgrade(&shared_ref); + + assert_eq!(Rc::weak_count(&shared_ref), 1); + assert_eq!(Rc::strong_count(&shared_ref), 1); + + // In order to use the the data underneath the weak pointer + // we need to obtain a new shared pointer from it. + // The `upgrade()` method returns `Option>`. + let temp = weak_ref.upgrade(); + assert_eq!(Rc::strong_count(&shared_ref), 2); + println!("The value is {}", temp.unwrap().0); + } + + println!("The value should be deallocated by now."); + matches!(weak_ref.upgrade(), None); +} diff --git a/lessons/old/2021L/11-feedback3/index.html b/lessons/old/2021L/11-feedback3/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/11-feedback3/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/12-concurrency/index.html b/lessons/old/2021L/12-concurrency/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/12-concurrency/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/13-design-patterns/index.html b/lessons/old/2021L/13-design-patterns/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/13-design-patterns/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/14-async-1/index.html b/lessons/old/2021L/14-async-1/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/14-async-1/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/15-async-2/index.html b/lessons/old/2021L/15-async-2/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/15-async-2/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/16-macros/index.html b/lessons/old/2021L/16-macros/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/16-macros/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2021L/b1-rusty-graphs/index.html b/lessons/old/2021L/b1-rusty-graphs/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2021L/b1-rusty-graphs/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/00-organizational/index.html b/lessons/old/2022Z/00-organizational/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/00-organizational/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/01-introduction/clippy.jpg b/lessons/old/2022Z/01-introduction/clippy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cf490ba9e1f9daaabae3f8edf2b01b1f7a7d97e1 GIT binary patch literal 27148 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 literal 0 HcmV?d00001 diff --git a/lessons/old/2022Z/01-introduction/conditionals.rs b/lessons/old/2022Z/01-introduction/conditionals.rs new file mode 100644 index 0000000..441aba6 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/conditionals.rs @@ -0,0 +1,20 @@ +#![allow(unused_variables)] + +fn main() { + let x = 42; + + if x == 42 { + println!("x is 42"); + } else if x == 43 { + println!("x is 43"); + } else { + println!("x is not 42 or 43"); + } + + // we can also use ifs as expressions + let a_or_b = if x == 0 { + "a" // notice no semicolon at the end + } else { + "b" + }; +} diff --git a/lessons/old/2022Z/01-introduction/cpp_meme.jpg b/lessons/old/2022Z/01-introduction/cpp_meme.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4ec2e1731afa9fb9042bfe8260e629dde748ab6e GIT binary patch literal 128164 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 z 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 + +#define LENGTH 3 + +int main() { + //# Syntax error + // printf("hello world"; + + //char* array[LENGTH] = {"hello", "ancient", "world!"}; + + //# Array out-of-bounds with a statically known index + // printf("%s\n", array[LENGTH]); + + //# Array out-of-bounds with a dynamically computed index + // for (int i = 0; i <= LENGTH; i++) { + // printf("%s\n", array[i]); + // } + + //# Doing God knows what + // char* format = "a very innocent hello %s"; + // printf(format); + + //# Division by zero + // int joy_division = 1/0; + + // int joy = 0; + // int joy_division = 1/joy; + + // int joy = 0 ? 1 : 0; + // int joy_division = 1/joy; + + // printf("joy division equals %d", joy_division); + + return 0; +} diff --git a/lessons/old/2022Z/01-introduction/errors_demo.cpp b/lessons/old/2022Z/01-introduction/errors_demo.cpp new file mode 100644 index 0000000..1c7d88b --- /dev/null +++ b/lessons/old/2022Z/01-introduction/errors_demo.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +using std::cout; +using std::endl; + +int main() { + //# Syntax error + // cout < "hello world"; + + // constexpr int length = 3; + // std::array array = {"hello", "old", "world!"}; + + //# Array access with an out of bounds index and bounds checking during compile time + // cout << std::get(array) << endl; + + //# Array access with an out of bounds index and bounds checking during runtime + // cout << array.at(length) << endl; + + //# Most common access without any checks + // cout << array[length] << endl; + + //# Array out-of-bounds with a dynamically computed index + // for (int i = 0; i <= length; i++) { + // cout << array.at(i) << endl; + // } + + //# This will be there in Clang 14 ... + // std::string format = std::format("a very innocent hello {}"); + // cout << format << endl; + + //# ... but for now, this is doing God knows what + // const char* format = "a very innocent hello %s"; + // printf(format); + + //# Division by zero + // int joy_division = 1/0; + + // int joy = 0; + // int joy_division = 1/joy; + + // int joy = false ? 1 : 0; + // int joy_division = 1/joy; + + // cout << "joy division equals " << joy_division << endl; + + return 0; +} diff --git a/lessons/old/2022Z/01-introduction/errors_demo.rs b/lessons/old/2022Z/01-introduction/errors_demo.rs new file mode 100644 index 0000000..bf5a394 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/errors_demo.rs @@ -0,0 +1,29 @@ +fn main() { + //# Syntax error + // println("hello world"); + + // let array = ["hello", "new", "world!"]; + + //# Array out-of-bounds with a statically known index + // println!("{}", array[3]); + + //# Array out-of-bounds with a dynamically computed index + // for i in 0..=array.len() { + // println!("{}", array[i]); + // } + + //# An unsuccessful attempt at emulating C++'s ability to read the memory we're not supposed to access + // let format = "a very innocent hello {}"; + // println!(format); + + //# Division by zero + // let joy_division = 0/0; + + // let joy = 0; + // let joy_division = 0/joy; + + // let joy = if false {1} else {0}; + // let joy_division = 0/joy; + + // println!("{}", joy_division); +} diff --git a/lessons/old/2022Z/01-introduction/functions.rs b/lessons/old/2022Z/01-introduction/functions.rs new file mode 100644 index 0000000..2987a36 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/functions.rs @@ -0,0 +1,12 @@ +fn get_5() -> u32 { + 5 // we could also write "return 5;" +} + +fn print_sum(a: u32, b: u32) { + println!("a + b = {}", a + b); +} + +fn main() { + let a = 100; + print_sum(a, get_5()); +} diff --git a/lessons/old/2022Z/01-introduction/hello_world.rs b/lessons/old/2022Z/01-introduction/hello_world.rs new file mode 100644 index 0000000..fa9fb84 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/hello_world.rs @@ -0,0 +1,4 @@ +fn main() { + let name = "World"; + println!("Hello, {}!", name); // using the println! macro +} diff --git a/lessons/old/2022Z/01-introduction/index.html b/lessons/old/2022Z/01-introduction/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/01-introduction/index.html @@ -0,0 +1,43 @@ + + + Zola + + +

                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/01-introduction/loops.rs b/lessons/old/2022Z/01-introduction/loops.rs new file mode 100644 index 0000000..8a02d72 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/loops.rs @@ -0,0 +1,55 @@ +#![allow(unused_variables)] + +fn main() { + for i in 0..10 { + println!("i is {}", i); // i in [0, 10) + } + + let mut x = 0; + + while x < 50 { + x += 1; + } + + let mut y = 0; + let mut iterations = 0; + loop { + iterations += 1; + if iterations % 2 == 0 { + continue; + } + y += 1; + if y == 10 { + break; + } + } + + // we can use labels to refer to a specific loop + let mut count = 0; + 'counting_up: loop { + let mut remaining = 10; + + loop { + if remaining == 9 { + break; + } + if count == 2 { + break 'counting_up; // ends the outer loop + } + remaining -= 1; + } + + count += 1; + } + + // We can use break with a value. + // Because loops are expressions too, + // the value we break with will be returned from the functions + let mut counter = 0; + let value = loop { + counter += 1; + if counter == 10 { + break 32; + } + }; +} diff --git a/lessons/old/2022Z/01-introduction/students/gasinska.py b/lessons/old/2022Z/01-introduction/students/gasinska.py new file mode 100644 index 0000000..e4989f1 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/students/gasinska.py @@ -0,0 +1,107 @@ +# sample 1 - different ways of removing elements from the list while iterating +list1 = [1, 2, 3, 4] +for idx, item in enumerate(list1): + del item +list1 + +# [1, 2, 3, 4] + +list2 = [1, 2, 3, 4] +for idx, item in enumerate(list2): + list2.remove(item) +list2 + +# [2, 4] + +list3 = [1, 2, 3, 4] +for idx, item in enumerate(list3[:]): + list3.remove(item) +list3 + +# [] + +list4 = [1, 2, 3, 4] +for idx, item in enumerate(list4): + list4.pop(idx) +list4 + +# [2, 4] + +# sample 2 - string interning +a = "abc" +b = "abc" +a is b + +# True + +a = ''.join(['a', 'b', 'c']) +b = ''.join(['a', 'b', 'c']) +a is b + +# False + +a = "abc!" +b = "abc!" +a is b + +# False + +# sample 3 - chained operations +(False == False) in [False] + +# False + +False == (False in [False]) + +# False + +False == False in [False] # unexpected... + +# True + +# sample 4 - is operator +a = 256 +b = 256 +a is b + +# True + +a = 257 +b = 257 +a is b + +# False + +a, b = 257, 257 +a is b + +# True + +257 is 257 + +# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? +# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? +# C:\Users\kgasinsk\AppData\Local\Temp\ipykernel_15776\331119389.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="? +# 257 is 257 + +# sample 5 - local variables +def f(trufel): + if trufel: + y = 1 + y += 1 + +f(True) # everything is fine + +f(False) # gives error: local variable 'y' referenced before assignment + +# --------------------------------------------------------------------------- +# UnboundLocalError Traceback (most recent call last) +# Input In [17], in () +# ----> 1 f(False) + +# Input In [15], in f(trufel) +# 3 if trufel: +# 4 y = 1 +# ----> 5 y += 1 + +# UnboundLocalError: local variable 'y' referenced before assignment \ No newline at end of file diff --git a/lessons/old/2022Z/01-introduction/students/grodzicki.py b/lessons/old/2022Z/01-introduction/students/grodzicki.py new file mode 100644 index 0000000..1454659 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/students/grodzicki.py @@ -0,0 +1,7 @@ +def add_contents(input_list, contents=[]): + for val in input_list: + contents.append(val) + return contents + +print(add_contents([1])) # [1] +print(add_contents([2])) # [1, 2] \ No newline at end of file diff --git a/lessons/old/2022Z/01-introduction/students/koszowski.go b/lessons/old/2022Z/01-introduction/students/koszowski.go new file mode 100644 index 0000000..2916f91 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/students/koszowski.go @@ -0,0 +1,88 @@ +// mutowalność jest wbudowana w język + +type S struct { + A string + B []string +} + +func main() { + x := S{"x-A", []string{"x-B"}} + y := x // copy the struct + y.A = "y-A" + y.B[0] = "y-B" + + fmt.Println(x, y) + // Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified! +} + +// slices i kwestia append + +func doStuff(value []string) { + fmt.Printf("value=%v\n", value) + + value2 := value[:] + value2 = append(value2, "b") + fmt.Printf("value=%v, value2=%v\n", value, value2) + + value2[0] = "z" + fmt.Printf("value=%v, value2=%v\n", value, value2) +} + +func main() { + slice1 := []string{"a"} // length 1, capacity 1 + + doStuff(slice1) + // Output: + // value=[a] -- ok + // value=[a], value2=[a b] -- ok: value unchanged, value2 updated + // value=[a], value2=[z b] -- ok: value unchanged, value2 updated + + slice10 := make([]string, 1, 10) // length 1, capacity 10 + slice10[0] = "a" + + doStuff(slice10) + // Output: + // value=[a] -- ok + // value=[a], value2=[a b] -- ok: value unchanged, value2 updated + // value=[z], value2=[z b] -- WTF?!? value changed??? +} + +// error handling + +len, err := reader.Read(bytes) +if err != nil { + if err == io.EOF { + // All good, end of file + } else { + return err + } +} + + +// interfejs nil + +type Explodes interface { + Bang() + Boom() +} + +// Type Bomb implements Explodes +type Bomb struct {} +func (*Bomb) Bang() {} +func (Bomb) Boom() {} + +func main() { + var bomb *Bomb = nil + var explodes Explodes = bomb + println(bomb, explodes) // '0x0 (0x10a7060,0x0)' + if explodes != nil { + println("Not nil!") // 'Not nil!' What are we doing here?!?! + explodes.Bang() // works fine + explodes.Boom() // panic: value method main.Bomb.Boom called using nil *Bomb pointer + } else { + println("nil!") // why don't we end up here? + } +} + +// ubogie struktury danych, takie customowe tracą type safety m.in poprzez castowanie do interface{} +// kiedyś brak generyków, choć teraz w znacznym stopniu problem został rozwiązany. \ No newline at end of file diff --git a/lessons/old/2022Z/01-introduction/students/tudruj.cpp b/lessons/old/2022Z/01-introduction/students/tudruj.cpp new file mode 100644 index 0000000..a5e48fd --- /dev/null +++ b/lessons/old/2022Z/01-introduction/students/tudruj.cpp @@ -0,0 +1,28 @@ +#include +#include + +using name = std::string; +using age = int; +using person = std::pair; +using address = std::string; +using address_book = std::unordered_map; + +void print_address_book(const address_book &book) +{ + for (const auto &[person, address] : book) + { + std::cout << person.first << " is " << person.second << " years old and lives at " << address << std::endl; + } +} + +int main() +{ + + address_book people{}; + people.insert({{"John", 20}, "221B Baker Street, London"}); + people.insert({{"Mary", 30}, "Avenue des Champs-Élysées, Paris"}); + people.insert({{"Jack", 73}, "Wall Street, New York"}); + print_address_book(people); + + return 0; +} diff --git a/lessons/old/2022Z/01-introduction/variables.rs b/lessons/old/2022Z/01-introduction/variables.rs new file mode 100644 index 0000000..3350568 --- /dev/null +++ b/lessons/old/2022Z/01-introduction/variables.rs @@ -0,0 +1,18 @@ +#![allow(unused_variables)] +#![allow(unused_assignments)] + +fn main() { + let x = 40; // inferred type + let y: i32 = 100; // specified type + + { + let x = 40 + 2; // shadowing + println!("x is {}", x); // prints 42 + } + + // x = 0; // compilation error, variables are by default immutable + let mut x = 40; // declare as mutable + x = 0; // now we can reassign + + x += 1; // x = x + 1 +} diff --git a/lessons/old/2022Z/02-ownership/index.html b/lessons/old/2022Z/02-ownership/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/02-ownership/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/03-data-types/data_types.rs b/lessons/old/2022Z/03-data-types/data_types.rs new file mode 100644 index 0000000..78cd053 --- /dev/null +++ b/lessons/old/2022Z/03-data-types/data_types.rs @@ -0,0 +1,82 @@ +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct Position(i32, i32); // tuple struct + +// Could Hero derive the Copy trait? +#[derive(Clone, Debug, Eq, PartialEq)] +struct Hero { + name: String, + level: u32, + experience: u32, + position: Position, +} + +// we can add methods to structs using the 'impl' keyword +impl Hero { + // static method + fn new(name: String) -> Hero { + Hero { + name, + level: 1, + experience: 0, + position: Position(0, 0), + } + } +} + +// multiple impl blocks are possible for one struct +impl Hero { + // instance method, first argument (self) is the calling instance + fn distance(&self, pos: Position) -> u32 { + // fields of tuples and tuple structs can be accessed through 'tuple.[i]' + (pos.0 - self.position.0).unsigned_abs() + (pos.1 - self.position.1).unsigned_abs() + } + + // mutable borrow of self allows to change instance fields + fn level_up(&mut self) { + self.experience = 0; + self.level += 1; + } + + // 'self' is not borrowed here and will be moved into the method + fn die(self) { + println!( + "Here lies {}, a hero who reached level {}. RIP.", + self.name, self.level + ); + } +} + +fn main() { + let mut hero: Hero = Hero::new(String::from("Marty The Brave")); + hero.level_up(); // 'self' is always passed implicitly + + // fields other than 'name' will be the same as in 'hero' + let steve = Hero { + name: String::from("Steve The Normal Guy"), + ..hero + }; + + assert_eq!(hero.level, steve.level); + + let mut twin = hero.clone(); + + // we can compare Hero objects because it derives the PartialEq trait + assert_eq!(hero, twin); + twin.level_up(); + assert_ne!(hero, twin); + hero.level_up(); + assert_eq!(hero, twin); + + // we can print out a the struct's debug string with '{:?}' + println!("print to stdout: {:?}", hero); + + hero.die(); // 'hero' is not usable after this invocation, see the method's definiton + + // the dbg! macro prints debug strings to stderr along with file and line number + dbg!("print to stderr: {}", twin); + + let pos = Position(42, 0); + let dist = steve.distance(pos); // no clone here as Position derives the Copy trait + println!("{:?}", pos); + assert_eq!(dist, 42); +} diff --git a/lessons/old/2022Z/03-data-types/enums.c b/lessons/old/2022Z/03-data-types/enums.c new file mode 100644 index 0000000..9e60c40 --- /dev/null +++ b/lessons/old/2022Z/03-data-types/enums.c @@ -0,0 +1,29 @@ +#include + +enum shirt_size { + small, + medium, + large, + xlarge +}; + +void print_size(enum shirt_size size) { + printf("my size is "); + if (size == small) { + printf("small"); + } else if (size == medium) { + printf("medium"); + } else if (size == large) { + printf("large"); + } else if (size == xlarge) { + printf("xlarge"); + } else { + printf("unknown"); + } + printf("\n"); +} + +int main() { + enum shirt_size my_size = medium; + print_size(my_size); +} diff --git a/lessons/old/2022Z/03-data-types/enums.rs b/lessons/old/2022Z/03-data-types/enums.rs new file mode 100644 index 0000000..ceab783 --- /dev/null +++ b/lessons/old/2022Z/03-data-types/enums.rs @@ -0,0 +1,28 @@ +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(dead_code)] + +#[derive(Debug)] +enum NamedSize { + Small, + Medium, + Large, + XL, +} + +#[derive(Debug)] +enum ShirtSize { + Named(NamedSize), + Numeric(u32), +} + +fn main() { + println!( + "Isn't it strange that some clothes' sizes are adjectives like {:?},", + ShirtSize::Named(NamedSize::Small) + ); + println!( + "but sometimes they are numbers like {:?}?", + ShirtSize::Numeric(42) + ); +} diff --git a/lessons/old/2022Z/03-data-types/index.html b/lessons/old/2022Z/03-data-types/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/03-data-types/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/03-data-types/option.rs b/lessons/old/2022Z/03-data-types/option.rs new file mode 100644 index 0000000..3c73877 --- /dev/null +++ b/lessons/old/2022Z/03-data-types/option.rs @@ -0,0 +1,112 @@ +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn main() { + let mut not_null: i32 = 42; + not_null = 43; + // not_null = None; // this won't compile because it's a different type! + + let mut nullable: Option = Some(42); + nullable = None; + nullable = Some(43); + + // such construction is rare, but possible + let mut double_nullable: Option> = Some(Some(42)); + // assert_ne!(double_nullable, Some(42)); // this won't even compile because it's a different type! + double_nullable = None; + double_nullable = Some(None); + + // None and Some(None) are different! + assert_ne!(double_nullable, None); + + // Now recall that division by 0 *panics* + // A panic is an unrecoverable error + // It is not an exception! + // And in Rust there are no exceptions, so there are no try/catch blocks + // Now let's imagine that we want to divide one number by another + fn divide(dividend: i32, divisor: i32) -> i32 { + dividend / divisor + } + + // We get the divisor from the user, so it can be 0 + // We want to handle this situation gracefully - we don't want to crash the program! + // We can do this by using the Option type + fn safe_divide(dividend: i32, divisor: i32) -> Option { + if divisor == 0 { + None + } else { + Some(dividend / divisor) + } + } + + // Fortunately, such a function is already included in the standard library + let number: i32 = 42; + // We need to specify the type explicitly + // because checked_div is implemented for all integer types + // and Rust won't know which type we want to use + assert_eq!(number.checked_div(2), Some(21)); + assert_eq!(number.checked_div(0), None); + + // Now let's imagine we search for a value in a vector + let numbers = vec![1, 2, 3, 4, 5]; + let three = numbers.iter().copied().find(|&x| x == 3); + assert_eq!(three, Some(3)); + let seven = numbers.iter().copied().find(|&x| x == 7); + assert_eq!(seven, None); + // We won't delve deeper into the details of how iterators work for now, + // but the key takeaway is that there are no sentinel or special values like `nullptr` in Rust + + // Usually there are two kinds of methods: + // ones that will panic if the argument is incorrect, + // numbers[8]; // this will panic! + // and `checked` ones that return an Option + assert_eq!(numbers.get(8), None); + + // We can use `unwrap` to get the value out of an Option + // but we must be absolutely sure that the Option is Some, otherwise we'll get a panic + // numbers.get(8).unwrap(); // this will panic! + assert_eq!(numbers.get(8).copied().unwrap_or(0), 0); // or we can provide a default value + + // Usually instead of unwrapping we use pattern matching, we'll get to this in a minute + // but first let's see what else we can do with an option + let number: Option = Some(42); + // We can use `map` to transform the value inside an Option + let doubled = number.map(|x| x * 2); + assert_eq!(doubled, Some(84)); + // We can use flatten to reduce one level of nesting + let nested = Some(Some(42)); + assert_eq!(nested.flatten(), Some(42)); + // We can use `and_then` to chain multiple options + // This operation is called `flatmap` in some languages + let chained = number + .and_then(|x| x.checked_div(0)) + .and_then(|x| x.checked_div(2)); + assert_eq!(chained, None); + + // The last two things we'll cover here are `take` and `replace` + // They are important when dealing with non-Copy types + // `take` will return the value inside an Option and leave a None in its place + let mut option: Option = None; + // Again, we need to specify the type + // Even though we want to say that there is no value inside the Option, + // this absent value must have a concrete type! + assert_eq!(option.take(), None); + assert_eq!(option, None); + + let mut x = Some(2); + let y = x.take(); + assert_eq!(x, None); + assert_eq!(y, Some(2)); + + // `replace` can be used to swap the value inside an Option + let mut x = Some(2); + let old = x.replace(5); + assert_eq!(x, Some(5)); + assert_eq!(old, Some(2)); + + let mut x = None; + let old = x.replace(3); + assert_eq!(x, Some(3)); + assert_eq!(old, None); +} diff --git a/lessons/old/2022Z/03-data-types/pattern_matching.rs b/lessons/old/2022Z/03-data-types/pattern_matching.rs new file mode 100644 index 0000000..215a74a --- /dev/null +++ b/lessons/old/2022Z/03-data-types/pattern_matching.rs @@ -0,0 +1,128 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +fn main() { + // Pattern matching is basically a switch on steroids. + let number = rand::random::(); + match number % 7 { + 0 => println!("{number} is divisible by 7"), + 1 => println!("{number} is *almost* divisible by 7"), + _ => println!("{number} is not divisible by 7"), + } + + #[derive(Debug)] + enum Color { + Pink, + Brown, + Lime, + } + + let color = Color::Lime; + match color { + Color::Pink => println!("My favorite color!"), + _ => println!("Not my favorite color!"), // _ is a wildcard + // Rust will statically check that we covered all cases or included a default case. + } + + // We can also use pattern matching to match on multiple values. + match (color, number % 7) { + (Color::Pink, 0) => println!("My favorite color and number!"), + (Color::Pink, _) => println!("My favorite color!"), + (_, 0) => println!("My favorite number!"), + (_, _) => println!("Not my favorite color or number!"), + } + // (This is not special syntax, we're just pattern matching tuples.) + + // But we can also *destructure* the value + struct Human { + age: u8, + favorite_color: Color, + } + + let john = Human { + age: 42, + favorite_color: Color::Pink, + }; + + match &john { + Human { + age: 42, + favorite_color: Color::Pink, + } => println!("Okay, that's John!"), + Human { + favorite_color: Color::Pink, + .. + } => println!("Not John, but still his favorite color!"), + _ => println!("Somebody else?"), + } + + // Note two things: + // 1. Color is *not* Eq, so we can't use == to compare it, but pattern matching is fine. + // 2. We *borrowed* the value, so we can use it after the match. + + println!("John is {} years old and still kicking!", john.age); + + // To save some time, we can use `if let` to match against only one thing + // We could also use `while let ... {}` in the same way + if let Color::Pink = &john.favorite_color { + println!("He's also a man of great taste"); + } + + // We can match ranges... + match john.age { + 0..=12 => println!("John is a kid!"), + 13..=19 => println!("John is a teenager!"), + 20..=29 => println!("John is a young adult!"), + 30..=49 => println!("John is an adult!"), + 50..=69 => println!("John is mature!"), + _ => println!("John is old!"), + } + + // We can use match and capture the value at the same time. + match john.age { + age @ 0..=12 => println!("John is a kid, age {}", age), + age @ 13..=19 => println!("John is a teenager, age {}", age), + age @ 20..=29 => println!("John is a young adult, age {}", age), + age @ 30..=49 => println!("John is an adult, age {}", age), + age @ 50..=69 => println!("John is mature, age {}", age), + age => println!("John is old, age {}", age), + } + + // We can use guards to check for multiple conditions. + match john.age { + age @ 12..=19 if age % 2 == 1 => println!("John is an *odd* teenager, age {}", age), + age if age % 2 == 0 => println!("John is an *even* man, age {}", age), + _ => println!("John is normal"), + } + + // Finally, let's look at some references now + let reference: &i32 = &4; + + match reference { + &val => println!("Value under reference is: {}", val), + } + + // `ref` can be used to create a reference when destructuring + let Human { + age, + ref favorite_color, + } = john; + // `john` is still valid, because we borrowed using `ref` + if let Color::Pink = &john.favorite_color { + println!("John still has his color - {:?}!", favorite_color); + } + + let mut john = john; + + // `ref mut` borrows mutably + let Human { + age, + ref mut favorite_color, + } = john; + // We use `*` to dereference + *favorite_color = Color::Brown; + println!( + "Tastes do change with time and John likes {:?} now.", + john.favorite_color + ); +} diff --git a/lessons/old/2022Z/03-data-types/result.rs b/lessons/old/2022Z/03-data-types/result.rs new file mode 100644 index 0000000..ffd0797 --- /dev/null +++ b/lessons/old/2022Z/03-data-types/result.rs @@ -0,0 +1,56 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +use std::fs::File; +use std::io; +use std::io::Read; + +// Let's try reading from a file. +// Obviously this can fail. +fn first_try() -> io::Result { + let file = File::open("/dev/random"); + match file { + Ok(mut file) => { + // We got a file! + let mut buffer = vec![0; 128]; + // Matching each result quickly become tedious... + match file.read_exact(&mut buffer) { + Ok(_) => { + let gibberish = String::from_utf8_lossy(&buffer); + Ok(gibberish.to_string()) + } + Err(error) => Err(error), + } + } + Err(error) => { + Err(error) // This is needed in order to change the type from `io::Result` to `io::Result<()>` + } + } +} + +// The '?' operator allows us to return early in case of an error +// (it automatically converts the error type) +fn second_try(filename: &'static str) -> io::Result { + let mut file = File::open(filename)?; + let mut buffer = vec![0; 128]; + file.read_exact(&mut buffer)?; + let gibberish = String::from_utf8_lossy(&buffer); + Ok(gibberish.to_string()) +} + +fn main() { + let filenames = [ + "/dev/random", + "/dev/null", + "/dev/cpu", + "/dev/fuse", + "there_certainly_is_no_such_file", + ]; + for filename in filenames { + println!("Trying to read from '{}'", filename); + match second_try(filename) { + Ok(gibberish) => println!("{}", gibberish), + Err(error) => println!("Error: {}", error), + } + } +} diff --git a/lessons/old/2022Z/03-data-types/tagged_union.cpp b/lessons/old/2022Z/03-data-types/tagged_union.cpp new file mode 100644 index 0000000..ae07b6e --- /dev/null +++ b/lessons/old/2022Z/03-data-types/tagged_union.cpp @@ -0,0 +1,35 @@ +#include + +// Taken from: https://en.cppreference.com/w/cpp/language/union + +// S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), +// and three variant members (c, i, d) +struct S +{ + enum{CHAR, INT, DOUBLE} tag; + union + { + char c; + int i; + double d; + }; +}; + +void print_s(const S& s) +{ + switch(s.tag) + { + case S::CHAR: std::cout << s.c << '\n'; break; + case S::INT: std::cout << s.i << '\n'; break; + case S::DOUBLE: std::cout << s.d << '\n'; break; + } +} + +int main() +{ + S s = {S::CHAR, 'a'}; + print_s(s); + s.tag = S::INT; + s.i = 123; + print_s(s); +} diff --git a/lessons/old/2022Z/04-feedback-1/index.html b/lessons/old/2022Z/04-feedback-1/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/04-feedback-1/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/05-types-reasoning/basic_trait.rs b/lessons/old/2022Z/05-types-reasoning/basic_trait.rs new file mode 100644 index 0000000..1c76202 --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/basic_trait.rs @@ -0,0 +1,38 @@ +#![allow(dead_code)] + +trait Summary { + fn summarize(&self) -> String; +} + +struct NewsArticle { + headline: String, + location: String, + author: String, + content: String, +} + +impl Summary for NewsArticle { + fn summarize(&self) -> String { + format!("{}, by {} ({})", self.headline, self.author, self.location) + } +} + +struct Tweet { + username: String, + content: String, +} + +impl Summary for Tweet { + fn summarize(&self) -> String { + format!("{}: {}", self.username, self.content) + } +} + +fn main() { + let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + }; + + println!("1 new tweet: {}", tweet.summarize()); +} diff --git a/lessons/old/2022Z/05-types-reasoning/generic_largest.rs b/lessons/old/2022Z/05-types-reasoning/generic_largest.rs new file mode 100644 index 0000000..7aa6a3b --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/generic_largest.rs @@ -0,0 +1,23 @@ +fn largest(list: &[T]) -> T { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest(&char_list); + println!("The largest char is {}", result); +} diff --git a/lessons/old/2022Z/05-types-reasoning/generics.rs b/lessons/old/2022Z/05-types-reasoning/generics.rs new file mode 100644 index 0000000..3198df0 --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/generics.rs @@ -0,0 +1,70 @@ +#![allow(dead_code)] + +use std::fmt::Debug; + +// generic enums +enum OurOption { + Some(T), + None, +} + +// generic structs +struct Tuple2 { + x: T, + y: U, +} + +// generic implementation +impl Tuple2 { + fn new(x: T, y: U) -> Self { + Self { x, y } + } +} + +struct Pair { + x: T, + y: T, +} + +// conditional implementation +impl Pair { + fn largest(&self) -> T { + if self.x > self.y { + self.x + } else { + self.y + } + } +} + +// alternative syntax +impl Pair +where + T: PartialOrd + Copy, +{ + fn smallest(&self) -> T { + if self.x < self.y { + self.x + } else { + self.y + } + } +} + +// Here information about the concrete underlying type is erased +// We can only either format or clone the result +fn cloning_machine(item: &(impl Clone + Debug)) -> impl Clone + Debug { + item.clone() +} + +fn main() { + let _opt = OurOption::Some(10); + + let _p1 = Tuple2 { x: 5, y: 10 }; + let _p2 = Tuple2::new(1, 2.5); + + let arr = [1, 2, 3]; + let arr2 = cloning_machine(&arr); + // arr2[0]; // won't compile: cannot index into a value of type `impl std::clone::Clone + std::fmt::Debug` + println!("{:?}", arr2) +} diff --git a/lessons/old/2022Z/05-types-reasoning/generics_fun.rs b/lessons/old/2022Z/05-types-reasoning/generics_fun.rs new file mode 100644 index 0000000..241c389 --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/generics_fun.rs @@ -0,0 +1,35 @@ +use std::fmt::{Display, Formatter}; + +trait DefaultishablyPrintable { + fn defaultish_print() + where + T: Display + Default, + { + println!("{}", T::default()) + } +} + +struct Foo; + +struct Bar; + +impl Display for Bar { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("this is a bar") + } +} + +impl Default for Bar { + fn default() -> Self { + Bar // well, we have no other choice + } +} + +impl DefaultishablyPrintable for Foo {} + +impl DefaultishablyPrintable for Foo {} + +fn main() { + >::defaultish_print(); + >::defaultish_print(); +} diff --git a/lessons/old/2022Z/05-types-reasoning/index.html b/lessons/old/2022Z/05-types-reasoning/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/05-types-reasoning/lifetimes_basic.rs b/lessons/old/2022Z/05-types-reasoning/lifetimes_basic.rs new file mode 100644 index 0000000..a4eaa2b --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/lifetimes_basic.rs @@ -0,0 +1,27 @@ +fn longest<'a>(first: &'a str, second: &'a str) -> &'a str { + if first.len() > second.len() { + first + } else { + second + } +} + +fn main() { + let string1 = String::from("long string is long"); + + { + let string2 = String::from("xyz"); + let result = longest(string1.as_str(), string2.as_str()); + println!("The longest string is {}", result); + } + + // This doesn't compile - incorrect lifetimes + // + // let string1 = String::from("long string is long"); + // let result; + // { + // let string2 = String::from("xyz"); + // result = longest(string1.as_str(), string2.as_str()); + // } + // println!("The longest string is {}", result); +} diff --git a/lessons/old/2022Z/05-types-reasoning/lifetimes_elision.rs b/lessons/old/2022Z/05-types-reasoning/lifetimes_elision.rs new file mode 100644 index 0000000..9633909 --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/lifetimes_elision.rs @@ -0,0 +1,16 @@ +fn first_two(seq: &[u32]) -> &[u32] { + if seq.len() < 2 { + seq + } else { + &seq[..2] + } +} + +fn main() { + let seq = [1, 2, 3, 4]; + + println!( + "First two elements of the sequence: {:?}", + first_two(&seq[..]) + ); +} diff --git a/lessons/old/2022Z/05-types-reasoning/non_generic.rs b/lessons/old/2022Z/05-types-reasoning/non_generic.rs new file mode 100644 index 0000000..c983e3b --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/non_generic.rs @@ -0,0 +1,35 @@ +fn largest_i32(list: &[i32]) -> i32 { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn largest_char(list: &[char]) -> char { + let mut largest = list[0]; + + for &item in list { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest_i32(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest_char(&char_list); + println!("The largest char is {}", result); +} diff --git a/lessons/old/2022Z/05-types-reasoning/static_dynamic_dispatch.rs b/lessons/old/2022Z/05-types-reasoning/static_dynamic_dispatch.rs new file mode 100644 index 0000000..2d9eeda --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/static_dynamic_dispatch.rs @@ -0,0 +1,47 @@ +trait Speak { + fn speak(&self) -> &'static str; +} + +struct Dog; + +impl Speak for Dog { + fn speak(&self) -> &'static str { + "Hau hau" // it's a Polish dog! + } +} + +struct Human; + +impl Speak for Human { + fn speak(&self) -> &'static str { + "Hello world" + } +} + +// It works like templates in C++ +// A different function will be generated for each T during compilation +// This process is called "monomorphization" +fn static_dispatch(speaking: &T) { + println!("{}!", speaking.speak()); +} + +// Only one copy of that function will exist in the compiled binary +fn dynamic_dispatch(speaking: &dyn Speak) { + println!("{}!", speaking.speak()); +} + +fn main() { + let dog = Dog; + let human = Human; + + static_dispatch(&dog); + static_dispatch(&human); + + dynamic_dispatch(&dog); + dynamic_dispatch(&human); + + // The observable behavior is identical + // Static dispatch in general is a bit faster, + // because there is no need to perform a "vtable lookup". + // But it can also result in bigger binary sizes. +} diff --git a/lessons/old/2022Z/05-types-reasoning/trait_default.rs b/lessons/old/2022Z/05-types-reasoning/trait_default.rs new file mode 100644 index 0000000..84ba1b3 --- /dev/null +++ b/lessons/old/2022Z/05-types-reasoning/trait_default.rs @@ -0,0 +1,67 @@ +#![allow(dead_code)] + +struct Upload { + filename: String, +} + +#[allow(dead_code)] +struct Photo { + filename: String, + width: u32, + height: u32, +} + +trait Description { + fn describe(&self) -> String { + String::from("No description available.") + } +} + +// All default implementations +impl Description for Upload {} + +// Default implementations can be overwritten +impl Description for Photo { + fn describe(&self) -> String { + format!("{} ({} x {})", self.filename, self.width, self.height) + } +} + +// Default implementations can rely on methods with no defaults +trait Size { + fn width(&self) -> u32; + fn height(&self) -> u32; + + fn size(&self) -> u32 { + self.width() * self.height() + } +} + +impl Size for Photo { + fn width(&self) -> u32 { + self.width + } + + fn height(&self) -> u32 { + self.height + } + + // Using default impl of `size()` +} + +fn main() { + let upload = Upload { + filename: String::from("notes.txt"), + }; + + println!("Upload: {}", upload.describe()); + + let photo = Photo { + filename: String::from("stock_crustacean.png"), + width: 100, + height: 150, + }; + + println!("Photo: {}", photo.describe()); + println!("Size: {}", photo.size()); +} diff --git a/lessons/old/2022Z/06-closures-iterators/index.html b/lessons/old/2022Z/06-closures-iterators/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/06-closures-iterators/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/07-smart-pointers/box.rs b/lessons/old/2022Z/07-smart-pointers/box.rs new file mode 100644 index 0000000..9a9f99e --- /dev/null +++ b/lessons/old/2022Z/07-smart-pointers/box.rs @@ -0,0 +1,18 @@ +fn box_simple() { + let b = Box::new(5); + println!("b = {}", b); + + let _x = 10 + *b; +} + +// `Box` gives us the indirection required to define +// recursive types +#[allow(dead_code)] +enum List { + Cons(i32, Box), + Nil, +} + +fn main() { + box_simple(); +} diff --git a/lessons/old/2022Z/07-smart-pointers/deref_coercion.rs b/lessons/old/2022Z/07-smart-pointers/deref_coercion.rs new file mode 100644 index 0000000..c5b14c7 --- /dev/null +++ b/lessons/old/2022Z/07-smart-pointers/deref_coercion.rs @@ -0,0 +1,39 @@ +use std::ops::Deref; + +struct MyBox(T); + +// We won't be allocating anything on the heap here as it is not important here. +// We're only focusing on the dereference mechanisms. +impl MyBox { + fn new(x: T) -> MyBox { + MyBox(x) + } +} + +impl Deref for MyBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn hello(name: &str) { + println!("Hello, {}!", name); +} + +fn main() { + let x = 5; + let int_box = MyBox::new(x); + + assert_eq!(5, *int_box); + + // String also implements the `Deref` trait. + // In fact, String actually is a smart pointer. + let s = String::from("I'm a smart pointer too"); + hello(&s); + + // Deref coercion can deal with multiple levels of indirection. + let str_box = MyBox::new(String::from("Rust")); + hello(&str_box); +} diff --git a/lessons/old/2022Z/07-smart-pointers/index.html b/lessons/old/2022Z/07-smart-pointers/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/07-smart-pointers/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/07-smart-pointers/ref_count.rs b/lessons/old/2022Z/07-smart-pointers/ref_count.rs new file mode 100644 index 0000000..0f97932 --- /dev/null +++ b/lessons/old/2022Z/07-smart-pointers/ref_count.rs @@ -0,0 +1,31 @@ +use std::rc::Rc; + +struct LoudInt(i32); + +impl Drop for LoudInt { + fn drop(&mut self) { + println!("[{}] Farewell!", self.0); + } +} + +fn main() { + { + let outer_ref; + + { + let inner_ref = Rc::new(LoudInt(5)); + + // strong_count represents the number of owning references pointing + // to data + assert_eq!(Rc::strong_count(&inner_ref), 1); + + outer_ref = Rc::clone(&inner_ref); + + assert_eq!(Rc::strong_count(&inner_ref), Rc::strong_count(&outer_ref)); + assert_eq!(Rc::strong_count(&inner_ref), 2); + } + + println!("The {} still lives!", outer_ref.0); + assert_eq!(Rc::strong_count(&outer_ref), 1); + } +} diff --git a/lessons/old/2022Z/07-smart-pointers/weak_ref.rs b/lessons/old/2022Z/07-smart-pointers/weak_ref.rs new file mode 100644 index 0000000..b2406f6 --- /dev/null +++ b/lessons/old/2022Z/07-smart-pointers/weak_ref.rs @@ -0,0 +1,36 @@ +use std::rc::Rc; + +struct LoudInt(i32); + +impl Drop for LoudInt { + fn drop(&mut self) { + println!("[{}] Farewell!", self.0); + } +} + +fn main() { + let weak_ref; + + { + let shared_ref = Rc::new(LoudInt(5)); + + // weak_count keeps track of the non-owning reference to the data + assert_eq!(Rc::weak_count(&shared_ref), 0); + + // `downgrade()` obtains a weak pointer to Rc's data + weak_ref = Rc::downgrade(&shared_ref); + + assert_eq!(Rc::weak_count(&shared_ref), 1); + assert_eq!(Rc::strong_count(&shared_ref), 1); + + // In order to use the the data underneath the weak pointer + // we need to obtain a new shared pointer from it. + // The `upgrade()` method returns `Option>`. + let temp = weak_ref.upgrade(); + assert_eq!(Rc::strong_count(&shared_ref), 2); + println!("The value is {}", temp.unwrap().0); + } + + println!("The value should be deallocated by now."); + matches!(weak_ref.upgrade(), None); +} diff --git a/lessons/old/2022Z/08-feedback-2/index.html b/lessons/old/2022Z/08-feedback-2/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/08-feedback-2/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/09-concurrency/index.html b/lessons/old/2022Z/09-concurrency/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/09-concurrency/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/10-design-patterns/index.html b/lessons/old/2022Z/10-design-patterns/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/10-design-patterns/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/11-async-1/index.html b/lessons/old/2022Z/11-async-1/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/11-async-1/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/old/2022Z/12-project-feedback/index.html b/lessons/old/2022Z/12-project-feedback/index.html new file mode 100644 index 0000000..2bbc7ae --- /dev/null +++ b/lessons/old/2022Z/12-project-feedback/index.html @@ -0,0 +1,43 @@ + + + Zola + + +
                                  +

                                  Welcome to Zola!

                                  +

                                  + You're seeing this page because we couldn't find a template to render. +

                                  +

                                  + To modify this page, create a page.html file in the templates directory or + install a theme. +
                                  + You can find what variables are available in this template in the documentation. +

                                  +
                                  + + + + diff --git a/lessons/project-showcase/fail-menu.png b/lessons/project-showcase/fail-menu.png new file mode 100644 index 0000000000000000000000000000000000000000..ecee14915a731492d321da8224154aaca8f304be GIT binary patch literal 200400 zcmeFabyQVr*FH?AN(rcdAdQrSbV_%3N=SF-CR9SY8$?1tK)OQ(kq(tE>Fy9V@vSX; zd(L^z`;70L_xImBa13OxwO7n_-7~K_mxd_HOWee`hXDr%cT-AIR2dEqlM4~%ICm-qhE7yJ+GWPP#aD}W z)U)XQ;h!{WMzF=zDo1>c`|0TX=7|T?;vtRcC2b)Nk_+eK_sOql8>PN*}ZT2s+UVQYH=W9E~W+spnnN#J^q4FquXke~a z|GZaucexJtg+X1ZMEM3%g7l?Jp5L3H4)##i`B<_%A!{u%*{}djL?aptSKa4b&zzO0 zc`XOT$zR2H*r7YT6S_^1^Q{A8i0XCOL-3I9>a2HJaq<)SI1JLB{xB?!B~+^=2mIYn zb%q+qn;;{3FJed2iLe(PL>E_bz#Pi!SeL;`iU&3yX z!kkkz-fi=)C5u0Gujdk^*1t=mAJO%_3o)7_c_0jP0M^IOW zVk6_c)Kfe&@Y`Pg9+!E z$r78^PB@vNqbOfKj;w~6h6dciHsRv@`c0ADX`wrWEe`Ei@H;a1@7&=!3V-z+d~DA- zdC@e(m3j}(oCc1oC5k5YHZ8ZV?}OI-=hTxHD6L4Ea5`M18nf`;!enUh#zO4DsGWwa zVFGw1PUuM}&jLKMkmCID4H-w#s{J+%IY&`%1$f%uNJCj}rLxDLL^}Slwu-LuM02VYKaimvFt;!b)IFGO(%hZs!&>DE)e2Z4{m6`#=3Y)}$E zNPFQ`@M{)c1f3IY#l&Czu=X{gqW(10XafJ8_ z@$}D+!xK|XT$ngm1H;?^R((y$xW|(L0v&b zgDiu>7K6*Y3kk$L;b7tF57L32fk7{8UpM{W`egAk^=ALQqgx{+TfAwUjm|$m{5TF% zr0{y9`R15#EB=OHJ4N(l?U#c5hW zhY5>Q(t2`lj{qA*g*{vH7)OPAg~AfY68cj661bOCTalrWVTf^9lU?gTD@8k^D$PR6 z*rPwxdeJoAqN=a3eJ#Bz+$H9aeBE>1mdJ-FLM~b^ycba?#l~+_b>iU!k*g>#bAxq* zoU6vBl9wA;7K{O=zx6gSC~)9utjGk~N3?C6Y#cQTTV7=ntqA0Z#}Op*H}WO(jq*M7 z6Db%a^1^hv%S{(F%-oiVmr44L^_+D-*WPYmuWxj%a$BrZubsXlMug8}+4uIPQt2e| zB$93F)K=}+sg8PPM?1&MxgV{cGg9=Ap+8x-B-on-{W|s+YwVoAA%zC;bZjI{XRz z&sx*{`!!wPF%0VucatrXNex72xmlAQF&q^bGH@}}ve!NqrJ;OaV*KTe;{HI`K*~V# zqvQ8?pXPr=|AF&^{*#?k7&o8%<9xfYcR6pFVv4md;<_a(+9q{)dovW+{!^!Sg2 z>OzV zN$ZJ9_OrRRwzW1lsSi>`G2nEE}lzuF(9(_%e1*zZGKG?tEjbbPMRkk8||Cwu#QSUehQF1y*gGEGp8nRRU z(#zf{{zz74uW7sXzV@Qf%aly^76<>`fI3Vb!k3Ki=mu${<0kbN8qB+myvytz)?<`p zI2cZ}yO^6amvq(jk38t?R@*ameYG#Yww5257I*U}*y#)FKG1fsGHvaeDyr1LFJ9B- zcXgS%x0EvU7*w2Ie)ObH=On=;&ZXRCbDd&@)B647d!tXw;mJgH>PTuErR;^e$|tsX zps!WE{;5_qckJjU_8f}r*VApDPOKHaE9$Djt0A-o)l)b~boc8EYHYJlYE|!dGYys; zO_epI7V#Gq9pBm1(hnT|V(ED#Kk4OSu+#ifyJOr2d>7n(%MY;}u^%LLzBv3LI8ZLA z@z(eI)jYZ$&wX<$Zxy8Kk7#6S%}hs44!An^4CaZ?e5PpOIj>(&8Y>H(_v}c_%u3U= zH<~pW?7UE!Q)$X)lXv5gv#19>J4+_&olnu}7f<5{F&#`M6R3B0?)xrB>h09oA7qcT zpUT`%Tw`i55ZFrv+ev8iYp<8M>s!>W`BatJI8TIF!H>urU^V-0p)7ySO;zHYu%(); zck-IsJmNj$opN*9YOdF?-~M`DhlPeEO=`){05UmvyXMv~b6n$9NxF@;ReQ#@wR`_b=FX`n!GR z!S(u5`ZpW(Pe0H0mb6S>Sgu8`f(|&2H}l)zfk~b=w8o> z-lSl)P{|sKuk|G|mO4!ZkKtT~|swwqMP7dxN@EHvb3H}}&GVlo=_z{37`u$lP zo)!-A*M0;zxF8ESB;wRUX zQzR3yb2KI6V0y&#h+F`JjEs!W(c~GAvZy%pbYP30+}zpOo`;#)&CQL;jg869(Ttge zo12^Y5i2t*DfUYU*U{XkqVcVP{JQx$aXVI~Qkua&pLx ze*d|W)70JKk2~2qK_3fvKxW7{%q&cgn15dzIF%2wmq*dU-PBr3)WQb947i5?3nv#B z->(z?_SGM^{L`tLf1Jw7#mV~TQ~&hUf1ax5Wa=nlX9L{SS>TTagP#27FQF&$F+-mH zPgq<5{cA6Pv;YPl^Y2v?z=%HkR17R6v4yCDD)1XnGsquAU*Ip=tKYz9cpK()uV|nm z7J`!!6;^eJ-xwE;Ruje+Rr-vDvJ=Q~W@uRbCF!wf*6TNO>c=Mt7u^C{-Df{fPxp^g zN#PNY(6Gsb{NVoK2LuFCls>pxyZA!3}xi%$0o3Bj? z8dI)K2?E4*RD#Bo>!<_);yNlp)3fUY4+6w>f(K2{t`j^65ZAR5w9>h*l>i{FYb96( zc1=3~HR(0&0OJa-X$QbCu4#vB+5zStuW5%rSiWo8;hJ{%6N7tAJ6zKae{z%8w8J&+ z081l*{Nb8*xTYOoX(SLfuW5&C+5wV1LGy=e+TogZfOfASZt|LTxTYN-*%Q=1Tu(b( z(+=0P!yoo=O*>rE4u9CgFGqPj?EsAz*R%r!i0f$wsC``14iF%&ryZ`R9iaa4ns)eI zRv-X#>(?(?Tu(c|%FJup0a9;YPdmW$;hJ{1rXBt$v#zHdu4#vB+Tjm-_?1uopQjyk zkOV+ylelW~f65x6tTb$oKfM2T3+SeII}PlMZJ@o`^0g`v_ex)afIJgR_>>5C!e5Cz z;Fwk_AoWPRy?Xa5^89uDw3PsOt(Q@*Q|dpUhqcbou#uZL- z{n-e-?R+LbqAz`QJ7U~N_5w(&b}(dMq4f_a5&^6Xlyl6W*Z*s!sskWb!%ju>H^gAY zj3MxXu*c^yjjQYXy8*|~td7fEN$W2Hh!#Y4e)GScK8p)rB@=pZ<4T^trap$R0OS(# z7AT>$$L{?rPIs5`Yyur{%xDQmhML>n#=#mjSS1rW;~|Lid-q zh5Z=;&!R5L4S4qR$k!vZRgEg=;i}JG?A!_m;d#2`w##tDlt!# zE3E$dCg*!GV3aJJ)*AM20eHx$I6_V7e|Vf{z;l?T`MkKgm%9XjdU{Dy+|?!*B>*wn z(9GZ04z`C0z^yq)vLC9|eEPg|b?xDLD`OWu7knHgBwcJ_Y$c%-Kh@Pxa!qp#1cZQ4)9>G_ih;k{1CSfC z3n+8sS(8mzw{L*6>5gTe#qh=^*BNA(W%i`a)a85kx$g_~gENVc$VL4SmeIH+tNq~+ z(8&DY5FStn`8$0fM#dC|gGa&^g7de>$!g`+l@E0x2fqDv$p7@$2gp%eeLVrtV?G1h zV_asv@;E}jt|LSPkCEmQU~&g?&0iP(AO0eHf<$W{5fx}c1ib||E5dEApdO|7*wE9^ z2!YFdTFlX;`R}5jkzo@9M+MIJFhDP32-yyI8s4}Ky{R*9R;w0`%8VV<-5*?uQK-QLg9ZZpMLGThUOZY ze^z-5y~RwLW5jhD-^F!W5gt<2p}A?`!yL}*`r@=)ixgHG4~PS`JqIN_q^$piY&uZ( z)~R^whC#Q*Zv#boaDHC~v`B||X*7QL*fGkb`CE9)Zi26hKHvAmG!a94p5;gP>EY6r z7H)h7d5LEb`{o$EoFL(=?rH3RqVNqWkFBTZH8&C#_WSW;sq)&NZ8m@sLaQRB=Djkj z%(p{1C#@Quq;p^022BA{!|zXOK86bVyaW!p@3j}lyBp9#{D~?cI5z*CgcpA>4nof{ zL^JJ^+K8Q=CplG6QB&yk6wu+Or!Xv07A0k8Q-XHP9X1QX2Bs<)k$9*LL&Kw!Dim@=G#m-YDfkaaWzB&+11rU=a;<;F1Nf2F8e#?&Njf+J{E&wt+$O6 z4#3OO8~*%p^N+_imHA8~xZF0?j|SOh^^5YUjUW61(@++|D0pmb+=GgYKm*Vwv(|U- zLbu5wkATLnS^ein2*xnsv(In4@A!UcEv;Icu5nGgH%uHUjMh+KO-O3PE4eN6jF+XO z!!5K`NtL1M@Ep|Ld)jfZON$Y^~5$B2J>qguEqp}w>^p}fpVy9#BA@p!zomi6Hk zlH$Pnj!EYC>O<&Pmpo%1OL#tJ?YzV*dcHV^TPlooqQK&C(af^l{-?HSZk|He? zr|h>LbJ12wge7CFn1$DYlv`gYCKW6qhFsQ}fl7oRcmXZnhi_qxD+f` z$-_^nIdm=TSx#bmvs0eOF+I^DKGQ}&M(O6x*32@&ZaEak;}LHiZbDVAk^qpR3i$to zpk$PPAG+e~B)4FRI5bm1#88~IZWS@>{u5Hp(Lx8?w-VD{u*FwsoUhvyXxBbT#v{Y- zM98ZYl}dG(XwK(Ab;^`;aVdBEL{Mf2dYtrCyhk_07)7Sbfa$m2t6%Q32_)@h6n&= zo%QKi5lmoU`JBsy=2nDb99IqEifHSWeI3sB`Ay~hgeWnR-Z{iHyVtiJ@eM3*au*e~ zM;p+}ainq;S><$|3pzZOQgtj(Dwe{HPa+$%D8P-)nBGcKD{X$D=2mJ^LrPMKoZZhQ z@Az!GgrwTC*nQWuK&!f0t?0t8Ze-1_EBH!;J4${CW)vAbUeGo47XsFhSW@pZY&#fm zciiNW@p4x-43LY1G^BJ1c#$e4`DJfKiJ2R70q}&#%8`_xMaH&$l~=MYG#u5m=wen| zLP8VG78;-WN_jE*W@0KOKWgk~u)_$nE#lC4@wDNbpQNXQ^r6FY23?s1$%Cm$g&>ah zw#wR)vg{|JK?>L!;Z0(^c4v4yi#H&iaR^7{jHouSscys-JE9wEoLMgbFUZK{9tg7o zXKi2!ZZ zQr`flcEJm}$H)Blcrc$)0nef6zY%^cCF@zgL>!TAL|5nA_)MGvA)0oUF0{AVtt2TH zH-5rtY~8d!u&8~v|2WR)>}Iy(SIXV`B1&o+oi5vkuQT1N+hSx}_1#oQNpC2DkdZ=s z%Yv2(2Q0yxdr`;PsGAFFYf=ZPh(m=Bh6um=ZHx^jyfPrX&>AZTO!yo?cpQ&+))-g9 zN8xWk2RrJ6_bdtz+5c+&Jj%tWb7q zjYdgIDkV_W#`np+>8XO`!8`8$3(3Zmt6?hfcy(#=bb3|tYneWJV?l86jPP4k+7BzQ zwAIhA1&|I*FAjp)e`^CE&9sl?Zy&}198mM%H9XX#IN$y`U=GUleT&tOh@AAN+bwZdymZd|FVc+AC;@Nj*(K3o7B#=*g(AVFr zv4rH0_lWAVbl;oqc4E@}w4Aff{PyZ4bilCv65x)t8S%$q8cYEQ;3gVw^_v{60wlB~ z!i7mJqylKL9Kk)P#6qa>3jTW2dHCeiu}kJmX0f*q>hyJQ%J-&;BVh+K_}eylNiBVO z-6a<9*9siNG!!b#Pg;V$M$CzRgqz_g=tLfA$~c-0pZ zR|F2u^(r}zxXk2;irz>t;iEZs7kI-Vsq}WN|8E;JFU z2<`Q-#5jL0=#s;a$e``p#)#+kul75s6`?#ig~tUQM0e3FS?O6^9(mCS&Ut%2H!WQ$!w8;L{GQl9SNVGOAKX3E|0 z@n7Ne-U+AM;7<#q(2(J+h1{wo!OQs2bcRCUegKEx?Dd<{^Lx8Kb zrUJTX$72EoZZ;AS;lg~75Gn$;IV7MRg|EQ+TxgY$L!6o- z=YFDAQ0G<*Gv?{{sz$7=?3|0VbkQ*%YAl|ySK~|G8CG})x`+kb(8NoDYE`~Vtb#hw zo5-fsynLa#+I6aSAKyZdSB(H&l~qlV(Kyb|!`7x@daMUfkbXW8@~hPN&$1mj)q_Opk%nzLqei=%m*?pYY_UyU> zATf+CFROUWb`OO2Ue~cY=b+&U1NT_VW7i$E)isIsi*JIw?vE2)#K~+rNpL|uN?i{y zXeI$O2dM(8=#Dq5zb+R9%finfEj&`j)8DGM2}x0!arj~8?N0!4IJ2{`q-upW3j9;V zsG6Eif+3|z@!kwr7O+1*p#`+0$c+beGK938s^?o^Wp1-NR!&cBpN~&tyw9s}-4<{F z2f#!uR@0yGS)qB*lmTT|fy`=(->9>1sPT(Mh13r<3U;=8IOYm|UN&A&7XH^uOarfC z^lrgMub8RL$};B6_fwnN`hbNv&<6BZBv?5baiZE^`q4#|Ah_Q+s&1{mBz{vixzmWm zA)PYg!iz;r0^Bo87ZV;Dfuq8?N%O1$@YXB*qPp^l{l-H|g8o|*Ba*7t@0R=`&JgJC za!9eg!SO!=th<^{eF3=QbHzEmqe!J`=$QsWC--nsI5GG(sI`%s#Fw4OW=3YnY z%qU?Ra8y^9dU~nE)BE`m5FFPK&?!!3*6=}UOiulQRyja8i>n(%07|!APF==fOs^1b zmJiFDUKoj17yGYOOUG&J=o4r$(}=pebIn^B1tMi6&XIahO{BNhyy6jueUIuk(%<@y z*X=z)K$=9Dv^u#1%R4iGMP4uH)P#xX2Tm5^m~i8B3{XIT8T@PzU~RsJgZNOfy$OPe z>kiZb1$-cjYnd|s&2h^?t@PU}9>@PcnsdrbV|NcDR2 ziTcA4o9NFZ4Q<|9~njTH(VA7m}rPZ!9GJAvs%>Jl%6XNtVZ#~cD3bY%g0Ueu_ z^Ybd^Bw>Y`%8mvQXF%;Mze@^tLO_)pu;^g&{zql(cMCykK1g~GxhalfOyEMbEC21Q z?KnbQKzB7Ua%Ol%<|25WIBhaX1TGvm>$9;b8y|E^Nbk*@%1lNFfvYxO4zU(^uW11p z|KZ4by`E>aNyPo#b?`8=rNHC^{IA;~Kt_u1I#l3e4h7{9}#Xe0jP$gVMIf@z8f(5B-5 z;4S`bTn!ZZ9D0H~u`jeJX-dQ)GnKa-4-H(?M?vkkC*+(|TxPs!Ol$hS^^n&Mns7*c z3_qt@Rakz-{a|{zxIRtJ2)trkpkF7P*0M3!$aE4h7;_NB#?Gc-yh=gT*1Sn&Dv!SC1SNPsyxsrS!0`7R+)h`%oh^@?k*`3d2!xBHT0SG0ri8~0( zrLfKE0N`b?reVpL079M4{o79EYTTN;>92Bs%w%3UV`BLI58N@}*{QCZYAu(qRr|CH zdni~|h8q%d4w__*SlQ0UGtPrZa~(g;5AAHpmyYB@)oU!@d|cOJvP>o!4@sWPs@JG& z!DS?^RZEZJg+?T#Apg%O{BP4i9y-I&8p-ME$K*;%;}jkliXMmd4&O(soV0O-0AhfF z@KUMVR*ld`{p_4ndB62@@OXtKn^K)c49}u^2=Cb=HNxJb&wGvq-b=^@UT0#xjV{K+ z^EG);X1o%=(joi23@!Rlko@(IrvIc3eOp@6TkeqgM1vfYpPN8fN2{c1ZK~#f z;P}5ZQXv{-qdq?Uax+==h`D!#2_LO&m6wogkhAw#DIapGWWSRdQZ>dK$zZiOHN`>> zwJ9KPrXm)^ME`UuWjQn5RY9lMB)_51l-)x?_ozLI%IuS4sY0z?vw?zBwQsT%@A;ldtqGn#0Yb4V5T}&xQW(udA8AQu zxK>b}@5(NY-ImLs3eWT{>Y-qiBz9}cIXh99u35a;o>1A)uJUZ+YN0=vu2HkxN@fJY zN2TTYW-&y0oxhQ^Jl=U|j*#FaAM=iGK7L=V>FA~E)Zzsu+S9ZC+e8#B%jwi*9i$Wq zfnK3w=k3G_WlhT<>Iy9=UnP>1L&4?xm);sB!x$p#=r@i2MgZx1;RN!Llpj9^-&lhriGKatNnrSMjF;kY*1 z-T!1jS8By8*_n3(yKG@0n2x&s>x8qqddOxAZ(H>tx5I_%UU@Q; zgA$hdO8^-aKwrYCs^qI`o6-PxV#}h%kV1VZcu5|gS{*VUerdV1`B?j654H2&8(-;W zn~n};fz7R>mk*AG$$ZTXr1N+Hu_S*e4`^YhEFDYYY@xR9Q&z32EWpz7neR z=})DuvP}cfGLxo3anIqc+L1NJE_Y}=7xHJzgz6u*kdOhOl81*T>`*ix`2lVah0CNm z_*ViW6ost3tPuA+_8W3e^v?6HzL?Kx9*vYo&7yOW{MxdE>CBeH+L8J8l}Fur%7+6y z4i}0!-`lsVH*U%Rgsq52`sN#j9Pc%~uErw7{@7@zVJ3VhqijdIjJY9x&gl|Bw2y}s zvymdh<5XJ+7uLNpdBo_(ZkFgV1jbdig!*-h`5RTw1ukZjIZ7NCjrApVr$i+PdL08BdQTWQO8F@jvGy zzAs|(Y%-31AD}(j21Shn1j^B}KEB3_;wBk{ln(tt8CLNdYJE!QM-9r{+wi6(Zmmt~ zc1oY2G$sJk$&KHc`YAv(y(^`80}BrD5UQ^AL50{Ai~$T$y90axdy?-sT;6d%u|B+? zZeQ{iLz6sS5jdo`43(79h!xqiNIq5WVKqOaOJvLF>WMPp6caiPaXxW}k|rgU2o3Fi z$t^wwJNZqYf)UfW5^egU%~H?JHxhTYGLbIJLBv*(N+Gwf3C583!b`v}XOEZdG}{V!aPFV#V1WGZ>ACJpjqgeE9F)geu()G9cxFzm?2* zRc2tD_^0(^NjgiHI}XPn%e3t-Np$hyBC3RG#n=*2OPO5?%PzfT8q0>54vTR}ZCc5# z{!I6;RWXir^+LdEk^xc3)iUB1b4fa;+_P8{J5B1rf`YD$h=3<_bx*TdM<{~h`U6S{ zmJnH~+zy+%wjPsiMTM>&(*g@Jl-Ns<_~}7Bmfh{;M8VbS@0C<;l4mRubRG05EC%-k ze*$dpPo}5_mlsK~-xQu7`%s>Hj)Tsmr0r7jX8d}^_a-F(o`rC|4s<(YEoH{EH=$xX zw|h0Np1CC^#moS^Lx;2`0`XM9WB85~&$;R%F;%yE@O*nsd|d|ou{QtXyO>Z+j)1JM z(I6o6cgigQ$-(Ep&_Z_@k^%a6(|OeTD&O`eLrXF;rrhof`u;+JDRBYo&e$SIT>$NN zi~J7{Wvg*Hk@g|}E>9<0 zyD5DJ9_t4&>oo{(=osvc=d(Sf^dazed4F~y+j-BeqTH+f6|+ol`C%7d45CV-m~Pdr zshXt2FH=UHy@U5_3Z(YH(_{d{?J8f?kC1nxXrUOC)tzDZPTPD@&>(ir>%LMui7h9o zTX0Tfoe~4;^I^Oq&{P!ovU&7a^yeU(uMNh*s{_*t$}Rh2m3R1;7!q>W%UEKesx!~F zs!lyw??H9y42YFx0_eXHYK9=R-f0d)2o8df{TFMTUy%Bf0nH=Nu!WxF!nDDwluC6e znt<}g`trs8VPbG6?)=Db%7$yfCAY!7?xWD6JaIl-xp*}oqlkUGK*^GyBN+!Scs-bW z7uV~{2V8u@_5GjUw?VY=6$z)4Eglm6UwIn@58rzUCM@+b>L&`GRE`ew4Q4amo_1$E zb!Hw=(j})7vBex!rr4~QrB^*0XpR{!jV$-ddes$=Ct)82Ua$n(J{DW=%d(Y2OVkL{ ztn@|S^2YKRWdPd~q&;94_ef zNjaqR%RpMcX=&n_0H^sgfAa->A~dznFw*~DIXPNvx8C*`0h268@ebw_WmfNU*2o+( zhaN+zx)p@XSCxFo)kn;(A?NeyLp!ISw(qkCA)ofYZP+HJ(d>e_^yVVDyYj8Ns`(zc zL<(%G%nYZqYB0vx@_$p&e@GD|DO-?ZB2 zD|YG+uc6;BL1Vq2Mh}FjoV5Dam8zkoL`6Nkc%pk|9|#jG8}g+Z8zhz1GrPwqk$p;z z>yiwtZj5VVXfko>m4BWYDlZ%3osh_sJo(m;Qnhk9G|8qDV@JXSL=)<~l@$XT`^Oy8 zyfH_>dUH}1rIW0=8KZjd2o={iJ}-M+BJ@a*(AFLI&0JRZ_Sfqf$c)u;+l(WA zZ*AgGEDwA23pBqnfOg?HI;rr2<~aiZIcRn+clXL$0Hfc!K$eLnXjmQeN8TeB^*mMq zsOJt(Q#ra)+K;RSnq1 zj(x19K9wJ9g%hPtTdgXyeQYwwYXSs5#d*9(?5?Ac8D4PE$2{QK7qzkjhaB_=)HH4P zm)~!eVVH6{Zn4>|fb@|{NT#yGIn(iiNj-CO4uP~pvc0=hy0^(H-oq@=7R0YHgo1_b zWE9{?E1?vOVTALRgRtQPJcE6gi<;2>A=D zn8k-F>})KcumUWDR}CJ3*Su}MEmi0Lkn+&M1AcpH{i`Rxg6kyjrGQ?h9=y&zt}CB_SPvRcsF`Ej4jy2|8xXVk$qF%VsckaQj;>QQC*q2rEQ&1 zgb&kYY(3X{U%kw3^UQ#3$8>%e{Zrd%{(hWZ_b@*-kgvV%IlO^uSFf(j)S}95a&olX zR=wu%x113|NqgUdv8V7pfD#Um#12Atw88-)jA%A$jQk2o;oD!vyjw)`b7;*N>edAu z8jt*0v6jh>)?QH>e<3SHehM^9RGUvdg)+11XCB$^;Kxi~7M|NZ2Dw(=VQ^c=V4k+kzWU0{h2W57S)Q#n`xH0ON-N2(U9cUU1WKT86tu%nYBz{T02zUa0ts`T<{@5e zd(&lkxK57k*Zs|id~L2uBK^l(73 zeoO0|R?eHZnn$uJcn34f$wdT`HTU`1)A)L~H{70P zl}ei-pmpMhB;=N?1W+4g2k6kcI+W7iG;|+?+4m3;hrOB;2x;!WM>K1=ib_a|WTy*n zD9xrxy6!^fR!r}g_|vgzm2ag}u&l1?*C_7Jbt_j`H;o8*1`Y3W1|J6O$A97g+~T00 z4glSId1C5e{pA9qvdf(}aS_TOf;hspJ4sl5(P>};cg9)<(2_@4@#wpWcj9LZ?w?+f z4oM7^tQKu3AFWUqOzZ^!oj-$C9h~Bda%l{3A|+raiV~1-V9ty6UGa#ynIRi^NTuMFU9_6^j6@ZeeQ?J0tRU_XG0t}>}9rw zgC^TYq*5x_)oVeSdh3_lY`q`6&3p7grEMn9ERUSO^HN@hzE061yH_`Y@+6)G#uoxK zEL$cb%m@Demd!{;U_HvaBBd&QOF%e|A)`=r91_tPQ#-)?`P1yFA7`K$dgbFSM)3QExs#^$zJbR zJ7w3Q@Fj?A-D>6Wc&^#ct237C-bZfX?v@Wgr;s&8K0YNVvx;^Z8s(!WJXw_}c{+pg zbKJ*3kb?iinB&DZmDP}DZsZjqVQYFntd(bxx-4TKwNwQdf+{!L_0ij#Dek;Sf;USnlbZm*Y49!RxX4m51F_^YWN|=_vNYVE8 zhxx_s7o^Hgm*S>dc81^j132>muDJfyW#r)29KaQS|J1H#Jkn=zsM9*MuG*QxB@XZx z0K4MdWn?;?oYhpP6S?_|@3F(y2&{0q9lbq|a-48*aUSPY1nVDSIb%C5?Z!N|$xiB7 z^Qs4G!J&97$mjt=6LIe@qgf`cmI{sevy9IvSZEu^A`h#!aluZd1Y~2-Y8?84y0sA9iOvU`*kYxhHr&ylo0p z(Q7W-rt9}(>pKh%yma}QB#C)Nm6_^=xZ^7FmOy~hE2te_$wbC?9!_aD>Rd0m>y?qE z=iW=(8}>N@z3pc6M?F!m_`SJ84gJJIDlGc_J|u8PNrOjja3V85J86sU$cQqBt^9so zu&+(J^Bc{6L5aGK-!VHYFf3?EYD1X6NnYh*fz3##qSq=@=%oW9bL@fe2yOn`tAQZ> z#G(8%)_v1MB61TK2ixlG9%!g9}o{@MSJ$Yzam(q)kgOU=&Vh?pk4XJmu8Ei&J!Xn1@rpy>&lVH$xlH4Wo zyvaBaY_GP~h#q6V7qWTeJUlGbxsW_}R-HA~96j{Fr3~!r(Rk{s#b*}H-q=tfQ%y8- zi7Q3Q*SbClp}2-p^Sw6lRt9*UCTU(eXE>$|eUA)1F91Ds;tza|Ga|W$pGX%3^TYqi z68_t9FeFVfv#*Xo{;SrfTy9dwrSD;o9HcUPvVXws*6T`m%T0x8LP?d<>!sZ7#ILy< zcq?QNIpyjF%VoL4i>4o(Xxva+nht17Es2loW>#}8059p#HMk_OVyQ+wdY74Vv{_6% zZBZ1T{dB%f?WxMqF3oI3R;6A<(IJl_lFOp~D4DmUX>) zwLDFAbK5(+hnGlnF-Q7n$iqm!`eBeGB)j_xWOrUtV>Gyd@4jQUJGR1)>p0a>UKSET zdc=K*qn6TP@f+XWWSpf#9SJmy-`wukr-W3Q8+c)4E`uh=iIx!>^4|wr#IuM8WTNJ_kYyT@pxhrgkBCEvU1_;yX|7;-ODcBZiEkF{%QQ2`VH-M$d=7|~X2 zQke7Nj#_CGFl|??v~+>uO;Fj+u$;l5RWp-EQm=C;fVwD(f>A!qfGeY)aTLKXR(WoB zTSG0~wM3<;&a65ojO2lX1j*ntQ81RE^a-L>+sR3!O}V5UFn;u;M=B%*VB71q<42G# z^;flI=SClFwTRmLFV!D$sy7|l6{K9wUexFvu|bC$md-NBHvkeHYn(82XgmG&$=#Wj z+K&z@?R8ei7d7zbolP8BjW@0u>V7{Ub=;W*92~5U(*o+abm6uL-Ql)x%juR4tex0aaRGBoaTI9!xV@L~yBO+F@+IgRq~icVeI zQ06jf1ZwJs;GcLqT8dWfdTw<&ShdcQlv z3eM?mUr(oU$F0wy(scJ(9?ZVj?Lub9bgU6rV8T_f9NwGgep${+cb|Q!<|SN9m*>I# zG80pazB$L*OV%gb5$C2zz3>wj00(gkn+2L4I!gnn$?rPAw#ojZT@HuvA2UJdAxFPx#UhHX(J`HK}07lp#4JKFGxG+_=i|aGuH5{qh{;xb95Y;jeCAwU+Ag`EQGc6k+u}IUtKQ`+aW$0gNJh?%_Oc;Uy^Ht1 zWM|A-n0X1)1TyX$kG($WWv9{vidW&d^~ z*3@{Fgpw(;qhe;d{i6WbfZ$Z2zK3360^d8J+++Zq1e$~^3BDc%*t?H|vAJ|Dsx=lT z3~%XFpq+!M59iL?XYds5YEQrZN@E=Rq+%YMHtyB;`6df`=WzQUvr0ZjKeUEt&_EYtbGh8_;n| zL(H6>yEGyB8QE#oYsDa$?`Np-9<@ki8ugi~{JQ5kmi+?KTXhD+m)@n_HF3@pic-z* z6CFwV#(C)OaY^eQp_pbK1wbj5xTyfG(TpbCo?Zyg!G+qKZg@84Ja<=q-znU-kN zPI;OOPEBa3P`o%7_aycE#_WG|q4Umj(*Q8b@4n$uW@*fpw1BqPt3jxeH?3q3Z;^M<^+F~Xds*K)p*6VaFqiD`^l zHDQYS+UFS!qn@tzp~d{KfPq9l3}AHYSGhGH4EQV(?7OgGIc#%kVAO!^hW_ult7gd5 z&?{UYXnvQ)?;i#R27F%!(KY~+kr1l+bW39bx9C>zjo(vz z?07&adl!ZIcQR}MB*RByAp%f7bs$6N$he!5no(}7*km&Wd8!7a^2b5B8~*#3YRPXoj9&r;I~YFz>Q43@Ajj%U~aN%q8sg0tn;gFLXKcY0kM65s6@_1@(55c{Izvd38@8?U&Fd<*ekVw zjgi#MOT#FVw-Abi-@Q8giV2NC$S~^PQYgh&ajtay_7SHh#K|p$6)ULKaZoGfv1^=T z0nk0X?H=k;v=-+R04$`dVDdiuVJtVl)m!i>5giemPU2z?b1IcX5NRH9k;xc_L*vhC z)@^G;fg`d`Ep{E*XBA6|B`C+Sl6FpnEj~I~$!v zy@FFn0O=oP%kOC(IU*)jIsS@8-)buXwLQ)H`($m!XKKJyfi8t*7_{_X-|@PyOL5rW z^rK4Qk%(QUT|eIGz8BWbaYrC?0BB~Cg0xcmk0f(vXA-6*W9$ z)FRZNdFDh@2(P#ej^t|>%Zvt)mN)J5FozfVAx1iLc^P66zAZ5!Do0-dm zOdhlafr}{MRf!Y|Zs6sKowaCSw8kHQXEJd=!&?(z_MFHig#F_tA4#!csu~a3h)|t; z)bIL1ME@{%Wjrat2xQn^i^wr7-ocJ05)Nf?H|~}K9_q`qduCfsK7FE2^Er1}v8Qe_D(fRtYMIlG z5L~Yv;Z6Apw+Yt*pM_3W@X7e=iN$4^B{@#oh6z_+>cv=shd|K?>Dn&)iy4(`vIjXl zuFst2v&iFWIg?`BHmAr$-gbmBPwCQI+SCyv7r=EZ8?A@dgz279?CKTUwL zv=yWBxN>2>h}}d%W1=Hd`XsKsxMZ!qhT1A^!Nx&wS8w;E1iWTN zN5o5Gj=9n76E52R*|Kj$QJuOy@bll=X8ub++~XXX{bOdu1JE^IyDw-^pJez5*uLpH zYkf7G><@=VIn5^t>2oZ8acO9dDR*!K_#w1x5U6rtl3T9nTOKtXF~1bxGYh~-v>`;^ zFLHEG36H-r;!UK#woPonwoYq)VF>B9@_V+NqUTakDYO2pb{!dxzBMex8G3l;6qh(I za4OoBKb_mdi@T#`ZougBfl`WV7s<3EVBIb{FWb>nel}C62lzK}j+_rw{A_py-9Vj& z{-D4i9YX(FE2e~l2Z-^;uuKf74k2$^xE(69Bv)n9ZYGyn?{gIBT!u}nxViJeDv$M| z%kvD?>D3F8+s{Euh!vD>xu?tsqrY-3^l1afS$(4CB4!v@j_C$qeia`C;jBraS(Y=v za%j0Jqda9d;!8`zM3f0NZ@js?U+o?P-|PYCF&VdehirOeJ(I{UR>vrFZuOv~wig3uL{lCUE<-jY3`K+e_7f;l-0DvYwYk-}dWtmAM=nx!e-p zf|0mGh}@HNu&VXEW}tW=FCQ+S)xwDJ z8?=y_3aoTSsPC!}`n)%W>oxkiOR2j?kiJ??2S`AXEZk;*cFO%+T}v1%RHyIXX&p1# zOepn{+e~WX0qUzHS%I526T4-qJ(}c9`Q7;!7p~I3-q!)8?Ul#0%e3#F1_3PuVK0SS zHJfKW=ikO(klY<#f9y^0|FQR`;ZVNe|8QwfQpr+8eJffpq%2uWkrajOyFzx^jWHxG zh*o3`Av-a4MzWNB-wm=1h8eO9GiK(whTC`P_xr#2AJ20f&zoM=Y3{k_y3YGNKj(hk zrN3qvoeHGROx#a1S5!2Kd$%w8^M}?RVc$>l0FxdY)&R|HmW8(qH8lx+QNINL3@UWHcqx6M86BloP%lKg%Drxia9Mn3z)9J?aeq z>7ck$nVohDMPRKvah^(LPVq2K0N)3WR>7H3s4Yj%8mOIK;M``r-GRv{U<;!cMy)n& z<43w}lyc7B=)d!6V%YT2KcBAG3K;b-cn8>qiMcbQgX|^URx4Qb_pz-8V?9bMxL6`< zUCLg?OMGs!FLO!JL0$fbRtG3=j4?~n8|vQEoOLY~+07GXMyP1M}mL@{GJig~TrK$A7m+keFv z@Fj&?j$8UC@C7WCTz$Yj?VJ4kGr6mi9?&R5`9#eRZl|*K9g3@BTm!1OJ;Jpwh#2o`d)qiECkp=M z{-Af{BZsiTvRaww{)A))(TVi8RgW58n@Y^dO}XA-7Uny32D`{s$i<{aS(a3zRCod$ zD|P7<5czPMc0MXs`(my0;lnq7FtJ?94Zi4!*qc)FF?Xe@8nhrc1@D_(Ix53x=&|hY zNP&eee%zBWY#F0E&S=}DB-t2i~nhu=CSW06!HMg1Km9P>Kryj&7Cf4w1ZnVyU2bU;*xXn z?K$tMRP#KpF;chG_1(K0Ka5=*9Riz9ka$hBWtC?8^@=VldY8Z3w_td&YwhRffr~F> zs5f3n%x!rw)ho~MQFLh3`)Y1MvXv;>aH((H<_&$qy3QrCgONVL=U}wQt&=<2GWz5e<$KAlx6_OzarZ{G+ck&Qx zqDNf9#|p~$W2JSs?YYdUf! zZsVX2&=x#+{|m;^;hm$r9IS=>ag&hfg0w<`QpUsmxYe{h>(g4l*IqK{1118Mn~e@~ zADsYe-I_wuHY-`b4QyTp-6TiPoDDNb=W11V&=VCEs!pm?a@qgJBINz2cJHjs0WM-z z(OF^5hG#ryCh)z7-oF+U);VI@)bJ`i?;_}yDvWL5qFEbB8;aYae(Lzyk{5oi{o<2; zI@7}OL!|ab+mYmRSpu6QLgb_O)5Bpo(##!rJV<5zsD#tI{`x%l^j7)vn8PpIKRy-Z z75~L-sBwHFvfw&?9Tkf>0q1L4pHh523y-_Mk25{$BWczx@eyVl zNFg2fAXzG1#_b!=j$83RwdtB%(gGdd8UpS&01#dqe{h3%N%_5eADV1)P# z(6C|u6>-7M=m1R*Dgy(X{?^?Rz{LXPYr7!JA@?y6m<|DH_lrt~AWgA7bT9^XmKb=+*x1piwc! z11k-Ro>7HX$BuDa8B+e4S)$*zOFx6lnUFuLM*jY`ZXgWQq%Qu5`0Rbvd{AsisW(Fe zaU@k9vBIC%918WCn%8c^72SO3(*jQ;=H$k!@7b50z89!@&gpT*p1<=_kAKZJ2iSIM zf|i9>jx??p(u)Viv%h*D{qpEU}0C zugFBxnliv?FoA=K587maE?|&#O3PCS5qCS&J8FXa9Zy5%gagb4TljHH^=}Mk%klZH zH~r0hdzbKDmg1I^F%aMI?ZkK8l51do%>WHt;FRX(uwq#GAu^6|W0Y^mnGz9^Q2~ta zk1`9x+|W>1+7Ru|Ig6B7@7^y3%O#6&iyH%X6)m5|B#RA|>2qaK6eYXk-Zx(*KbMFk zgjo{b)}g2p0fCA4zq@BV&)-jPqWbGByTQj&PeK=8qU)^d`t-=V-qBO@dFt<2-tilq z4Q9uvO?d9YQ2Q4fSOco(HoHI$pH?0qu4!SkCOmi24=2z?%K$IL&|S$Y)cy|r3r%kU zZ~7qK_&Cy&*7)9BCrEg92Lajfb$p-!(a-6I_2h~}FVyRJ<-qq1C-t4ktcNkGgGMm| zDU8Qaw?Vex5=uFA`b&2pf@qgRSi3p{qbY-_?Be^!%2guP`&18ID(QEl@h6^4vNSKh zs6eAy{`fFkE_3c?ZV5D074gCFC2-f2BTO6G5M*88(Kmm#>(){e#j6nfUXf0}f)wyq z1mZd^YiIHnjiTLtJCD>4s@{^hMX4IA)Z=}z(Es@3lrz!_1V%-)N}r!YnA*YWIo#DW z4jE7zQ4$|mt+`prZ)qBUa|6~(9ryVm9?XFp zSnfXqU2+vjz!QqtC=@Lm5Td6wcG9+FBR0Np`Rpqq7!htgl)#nfFreXx@5`Wz55hDt zoaGP$T7$^)oU^VzG4A6Xt|8i~rC4vlmjuK)!Q}IEPPmJH1$>@jot;Ww-+z;oQr~p6 zaLRc24KA9y;s@M8&|s8Vn6;bI^sr8)lTga{-iZJZhst}d^$=9WV8|rt9 zF7WM+l3T7JpW>A^aAMFZlmC^)k@{grsxX0odv7E&*Puh1^URT*fAlel&{DYBz>($B zXO%dY%6TbQ?qbrQ^lf@Ky@YdXheX>-Yj>S~Gf=IVh@j1rL@;zPN|OIuwN_w&S2T0| z&79ay5GnNz^K8lA7=M%F+YYtFX$22IDr7A5+*RPCTokUd-J>~^Mg5jDpMoVkCAlyo zF8(U$eZ4svqvm#Hfw^st01_t;RQsDuI!vLgMP{MpFaC#Xi+Z5A384SD1hIitJ#Sf} z2iYf(crrOvusb6fq;~3h(qM0ba9QfE=Z2_JJ(|*)APi@Rx|u8uC(~WneU_OFw|<`Z zYu~`+tamHu95_s~)o*dW_3*_TV$a^Jh4=h=CxY3Bmizd6Oz2G-NY>*@PP%_*Hm;d< zeRF#OMyw}V=x1tpGVkeQe^c0P#l7t%1kne!0D;-&Q}=4qg|MW%5QsIKP4EBmUm#{u z>?quvw3K2P6qHoGpva_ddhuQ8&3P9ydW@9h9ylhw`kbb0Yjw!NHkynSeVCf_BDeJF z(E#O7^I;4RdzLal0^$cv_}g&6`n>uLm%H%Zn%YEs4t5Qr^lP#8jdRzLI^6Oa51e?+ zSW9PudF{ik3sY}p9)4kXT+GO3!$|s;pH>pUWWajhpoS+w?bCU+cf8jld;<20Iv9Y% zeqCDcY3Uy{2ry8}di&&w67NFEw{trmHQzG7Kx`n#kVkm1G1#aD83MMbXq0CNK9PzW zZG{cp)8+|yOuR}9U{rLo`leIrvv%IphGlhhFL+@q?V*^pilLf(_;U?W{ zt2vW{d|eq5J=(rq(fKcX*<-Z|zxVCp2}o3oHPGgnzKR=?xnzzU+lIinj(D(FlS+_X zScwO0dVRGu1I_xJt!-*YV8Vlj$>MGo=`{y_ zPr?ruYk7|rcpS3v2bPV@@;2?d5*CYYrn7r z$mjdBpR+;9A&r)`myBeC-&+{vcj9cOm=wy!B!m|h%fI0lRHaT96UdFBm@gw()GT#i zQhe!2rORbBWpJ`Io6SdX1dSPzcarhGK5`Rhh4eT1F+zZ)GrN4Xn7tEN%mcUpUhZ?} z6yVyaQSl8*&e(y0p~=t5iFJc+sRHC}DK9-fIXc_)&I(NhC7AxSgPkj_Pvz-i(6@Nc zK77vR{`tKp-8?)SNW(`En2`}_=I1dkII>johX4^-N1dPunGBG7Wnr+ErAoI_L$W@@ z(HKAF%o2$%#0aPVQrtOr*dk1VQs-pWu-xA%os*n)p4;1OzP$`*IA$EnV1^;73R4CN z{8GsaC2oq?RW0@|)}wqvBP|HiUz~<|g%tskGyzQ`gtZCcGox+Rp!DTnslw*|COGkK z4ydZiG@s2CUp|%<@{n9!=I|piwn(}QsIX7qN0Ee+R_w|yxip(Ec7=7`DPprckTTk zygVhzhIvpOhCZ5>MbcOoD|L&S8EevhfkxSxCzI6K$6Wd9H$&6~y^Mm8T}>|C(}t+a z6X@Aj#VF5RdNru(^hm*wt`{uR?-Q)4kF^)^Kl!}6$}C^)Dq|--i*&)U3O}lQSIn1b zR4UGfce5Fc@bhB{cj)jIUcHnhSn9rtE$6VdTk$e6h;wA1AhufmsI?1nF(PS>9(8Yv zt}R{VF(dhsWv3=tjFOfgL@%>oIA>{dzxYIpexzMz*FR+7M!Em?lo@kAsdUQ4A1he4s-CkfVkD5x{NO7*&c4wwR>E!Ius}wJi>f|( zSUzWQG8fmy#T8XC<`fdR2j*@#QXME*bfLJM>Q`BOb#yz4%+Rt1daUte@Akr-G0xb0 zEdtxIT5js61XV8yT7_8xSv4@$-GRgCcG2({2W`fplkhQ_j~hd5nbgTI_C`Dp$&dAN z$U}P(D@z26=2>#^%SfPD59o?zRm={lPOOiQ6Y}ab^iC>Y-#xpHA zrFNbdA_j9NBxYpH{o3Hl0~36h-Sg1a1V+M_$@uyNoSy8tbTPfS*$2&m!Ng-)g|h-o zkC&bnUbZXZSGXOmOEfeHWUG#MW6e@0#%D-PmfhJW{!2o#CY?E2$GtL@XYGt;jFSg| znqh|aEGe-X8??cQf65L`M$Qc5xGdO~C7YfD%xG_#nw#{a?r5{F4+NZ3;|{)9R!%(S zUM%*VPL$*9s<3CI?X;jo3wq}rBJVbF@uhfmvwt;jwn!Nu3X`J=eOtBdw?dB9Aa<0~O zYdGAb{+_#<%gDseyOu{fk2=Y?8JMh;E%Xn)Y+}rsB{rE2%@>E~6Ab;a0+bF5vspg0 zzP9}}AQjp!4UtBy?aW?UBYV!{*9x=|OBwzy{=SS2#Y+Jk5)W<;GKysyurFZNFvXX4 zal(X%$|%^DmzlI3AD8Mwt1I2OI#+l_b>du}NeGhz7{w&MtcC>2xH~!{2uM-bzV_F> z1qR15SopdOD6QbIAvT^4H{%k#zn@f(<2V0SQ45v9GJQMZ|02ORDS+!2Mh z%ZJdU^a(J6f30G6FEdMUj~FjuzB%$3t=_k~dw?SZGoOJjT}11hZ6QBdkT4>-=LK=; z5LFBq*{b5VseIOR%Fbb+_`m3;ki>Gvo{JpquX>BeT*wrd@TS)A9Yg%AzaD19VqipR z=Huo{(h`_8Gs9b089jOUFs1)%1RTj-uUh`mF5}=X3nbpG^|H6upq{;U&R=XZh--to zC-;-mZJ(sVp?A6cU*QTX!zi;i{FX;Mj**a!*FtUSem%akaBpO9U1gAUb4Y8yjk>(o=+uH`>Md)*6|;YmgNBU2=35pi@LK~ThII+4m%ut ziZ>QvbIZMTfl)OaSvl282^?bWV%^Cr^tX1koO@(=tr3Ic$gA#5RUSm^CL0pLm*Utot` zId{odi6HwIZ@GK-)xb_!l2W?(!kbD@75}r?V?3j=Xl0XnoHy;6_M`790CM?*5Liyr zJ{kKo^ioVrI58%{Y;^6x5)PHH2^xc>r{nczBa$HjG5DC`B?az9!!upc-qjMq=Fetv zF)g{?@=|M0DI4$`E`~mr#IurF87PS+QYP1i?*R?0*%KuD8E{BC5WOYuXPQw+XV_3% z;m*ByDYA&xbua|=*yxDj$}tXUU36u7Ec4lgasenbZmwJCT$aQ0u2CkC2JX@J2upv z*@$&g=!WmZu&9G(v8#)fXA&IHvdc=l&UcDcCAfK)WXkm`yS<>J^GaUBxKXJ{mp)u?(3%qg96xRM2|ifh-S(tT zX%k9YVvfU5!Um6?oLqkS1HR@oQe7{LR7@|TF0Y#?-e_0%TWiP?R>ADC8r7=eep*>J z=5u9UeRDvLB>s*&8O1DhSUE(ZB->Ckj_6hq#1ax5`np;*($KwWM-FwDEG#iGhu~>; zs~?x)Z=JD1w6B>~wmXN$#{a{qfr3uu=L2W8WVZJe(|si))oQHUn1|XT&Ui zokd9ozo>oeJ~4L-D;~EurBTWY(SSu)$x6Gflg}IKx|1Oszo!jLXt`i=%UPci$8iba zIsb@Ltmd0N!hTVz?VeZD0Zo#Vo@aZq>8u6%@{{w+i1V>11o<-rLh|QeX?-s zTdSy(`5@<_vwe^UoEuoz5?mLjhr^~}oIivbo?DYweU6vqKPQv?^}Uh>_c0bXgh_0g zbJk4ID*PA-%j9*U9*vw8rs_ztVjg|{fUSMXLy6CpdAB1LC7&{7xM8mLw}0`* zY2#&~AWi_FR64HNwE1pSDcX zQ3HG11*K2c$c#?;+Y)7T+`nR;v3Eu0w0QsYZKc+Qbqc3r7DIkcQh5>?%3}Mvk?>_z03+a@~jlTP#GJNzEan1x}+$pqpihJSka(r z$d-_FI}JWkQ`1eMGUtrFQfDLzb@&J41fS<8H)J6DG095kap^?Ly{)mR zrP|>$5a7_`hML}D5r~We_|quiR>Hf%mHewfn9k4XZ@d^cLgV8sszkB&^)7b2_qSi; zIUwF;#7VH#@O*K*3pO-l- zkf0##ZPU)9>9vH*A^p-5mA=R?3y0Y>$v}})iN{E@VyM0rxnO<=O?0pC&b#4o>}?eC z{7IZ)FUsLAe;=)o?j48tr3=Vq!ybKj+XuzkDg&cJI-A&{JXLH~ zru^tm*xwH}| z@{e7LR?I2!dhCvd93U+4J1n@V9*`%mKS1 zUyDNuw|G)$D({=wPg;M*TzV%Bp_=YaQ{0Oy0#1$d6Y=Muwm~I#JKn5WuL}J|MnzKBMOUy8w#1Oi_;IeC%U<g@~-KTadXt z$5~>Uwxb4(6%ZabTIMfp4#=V@rk9V60!d=$W~?>RW<;}l&3|&ET#)Z6i=~JN%AD^r zZ|?h<;pV;2-?}=&nZL4@A(1niSaPlQY%Mz`{#F`>*Q<*y_^K}yp}zvIwx97}C`9T4 zJxn@Q_7VzM{a6n;aHmJ%)}c#oVecYq_S8L{`Od7`>3aJVt~do87X4_1Y`T`~O0BQwTO&YT z?{JP8OR%@rEh<(^I*uB~J{Tf(h;hG^pl4_XwLZ>-W<>Dk3pTDnVQVLC^F4lkl|}bu zn?B(0DOq`u?*e<2t?Iky8J^|s&|F`oQz&x29tG3&$_F^?kKsdwc#haD$j~vSAlE1qfUfo@OFb!7Xv0#1F;r@)|(1G@4551A-`u*wT zbOA1Z1_;ZJ1D5XmS}XvOd34uG(vx%3Bc!xKoQSpXT_8`uVMy&K~ z@(1qMUAWq8J9*%0_u7t}u{`FQn$>!el>M1NfeZm*YBs{GO}6weU4;T^SKRGwRq{n$ za`;Ol*=|*1-RLCzX#+;~ns`b`NT_gvY1i#Ax+htTb@9eYwtBR>0MP{Lw~;IoLOO*E zbE4vUz58^1H|^bsEgN#tY<^O!TnpqnulA?81^ytoTjw=~A8c*=wIWa=sZ|}&JaiCD zRQHY6Moc|RVUJ}SbtUyz3c#eWkF{xjvFu&-XMzSTLc*7u%EO)s}}wk^`ycd7XuyEYL7 z)O$Ar>MMYyOpjgkHWd8hLwZ2%x+n^c52f>bpC&LK*^e?$t}A@wc_D0IckOdwv%Oo{ zqFfDU_tX&CyPO1r23)Y=I%KCM0ow%9Kn>lL{@4+AorpkBEtJNc$uC=574|@vi8A{w zEmr+ZvwyCL_UgXFFY+0lS2p9(I$u6IZP=e{BHsXCfSV3@+XtMbeX$sH63x_OXWTC> zEGnpNSRfMx92IJ+EUsOv=KGJgR8Ql#vBhkHsXKac=v|@`jUn3(fCQNiJwbNZP?+}p zZ9G|PVJ}Wk&r)`ExKBO6NNwfGAcpJ)(7V-R1f^G^;o9v6g4evp6rP5ceHOpI*-Hv} zYG!eEA(p&TK8=zB%{uZPB9>b}!+r$y&FTnKCgpM7DG%s2bFxsxbov8dRk&@eZUK4& zk(c6&QE@WjXPpPuUR&ZOKTE#BD|Xea6>w=6 zObiciH~0S8R*4jm4sosiX75QHwkzGC^%6n0HtnMlCW#H0p&fy+;)})QPO50E=G2qk z*b-6Q+K{x8L`52^&3H;T_y<`7Nc@_USmXWb1zK`zlI?uEcj{Jwidke@-fM5PP>ubljgTyd0ofy)R#s~;u^Y+_$FoK2`M=dQzZFna zps!Q-UXiwvtnGD2;_E;qujtuZ5`+~F+M0o=gc_~Z1x>xpPwQ!Hr7ReA%bG9-=a+dF zgqJp>uk|-P9@0Z)&$a2<2clw0-L-hp@ojunD_H3QYP2<4i#^KKj_$)O;pE+&muqg4%H#QRj$N3PJ-yu zQa)MC7j_daJ(Zqd_HzjBP=U)JQGplXBzt)nS65yEKVe#zy{pz^^DKZJguwY`Owp@y zv7Vx_4rYbsH%-OZpm6C+x_z~Z#BIoQJ-4|mhK%MOUUMT)su8o)6et9(N7ZB{#b*=a zJ&5J!4+#VCK>K{q381|aoB&*n0aY9LIAg+SRRUu{&IG295cl>Oo_J^Es-E@=x`MQe zaa(C5CW$yzmsSpUOD`HtYo(-lM27A~+I_%qn=QLP2uj=Wz81fdSDAdBNR825o@(x_ zY&7y-Gc+4ostM2U*5g4^#&|r@T)8tVpb^{shEYLY$jhSGqWo-v3v$JbUt;Cm34>g8 z z7*&1Bl{(RHSgd?Y^5?LCcf`~vt}8~P7iE0KMmt}sSWEVhG%DH9Elbw`{uk~uhp@@j zJQWU}lQk~`LmkZk0H>h3^_KHGY6&zfPw_-!;JBFAg)Srw10EMb+7+#P$CmK(qi&hG zXK`2UV>6W(_#wg1S}J($Tr_+BSRin{HLD|dhFEY|*z=cZT~*(w)Z<-9i@FZT63a*t zKJL}tGJ1yRZKSOg(@XEcdefSbU2OTN>0Pox@3H!KwTB|E(*0}r?9{v-$*7scG(X3= zJk-{nD{DVfg3(|crz(%gTt+WNn^3+emDThamcSdtS9~h@9^1R#o+WlCFgFLf5M? zFQ-Lv2Y1bySI?Y>o!iGwj2R#s64ojd6Ov1?d%E{`2Hu5vs5D4Xsw(?4R%81ty3Vq* zb#dOE)9K%Rj|gEL36z-d%8D;HEsg`-;zSlb-k>cX0g@NFtw(0vzvB2<(ZL+cO$VZF zrB?2$1g1NUlEa@XlWXm6yJbk)^R%nVoKxt09FeltP5#vQerU}#y=eL^6QeiN{j3a0 zTh3e_chaDIdKAtt^N|)n|Y6Gn8gF$&H_ebjp&2f3Q+h+dlXZW@$MiqCYv+P{$h`pE3v5O0E zlj-ZpHHFbMJ0DY3Da1$-`+hP@ZEVk7&n(_D+V}94pJ5_S-v6oEQPtM&8!*mYox9`W;4fvw{P7McCFh$_G~({g~=j!N%z&JZSHRtG)4QD zl4Yyg>N95--0t<`n_q%FBfGHawb-x4Tc)y08A8MT8?eRLLz$_Rx4eEO=o)2 z^Gi1~wJkBAI(eO(v#aI_d)de3!wq+t3~)ch2vhiA6i}fw+LHB;r`RL|Z`Yu~`G=}@ zWq8~r+0}>qvXpNw))HJcT|`j+cfMA8-9pitTy-TRWkC<5zpr;QlSt-;4!~`w>amb2 zb4XhVk-k(+pvluEZ4^TZ4JUO;7p$-;+m{J+dH-w@kdY;_NM@psgXk**{W2!T-5vdn z^H^L+=SoOs+g&5%2?4g;L zmoMtv_!8Gu9TAJ+Op`@gIMaT*F&S7}+hd@_*AhGulfC@-ZSyT}S&H2!*Q+As?4H}+ zi0qdY(p6v*92;7i`<63V#%I6BzCEVhaX~RYBOw7#g%=n991$xov9mq1pWdyY!$Y}~ zr(#7Qx?1zN3x#q!si3jM8=~m%t)EXs#SZ{oOz8qzWtBF7ddA3kOSPO7uaT2d#VGglYPT1!;Zwfd&b+GSn6gH}PQ za41^|fUoiFN$YJ$dCdVL+9f^g zKfnHY&t>0yt=Xf;YLDf(h@D-XUQ!OLsYHYbdUQU2T_PpTi$_@mdGxi%yQ~$S&_j!L ztWEOp1S?vPe7#gav0mgil(Q{!1NuPsWzX=Mf6D zW`B_TyQ$}{^bhyrm_%joFp45ghQChSW1nNv%1%S?2nVr?=rR<%XR&yj=J+4h_mkqV>c`DBsO4G`W4?pvYPz?7$R|mZ>SGP*in-If1k!57aBprLfpmA#nYiyE z(oQo*F1M6jwM;xPpLd{yT!k8RCU2$r(Z8&)aio9?g>@ zw3{X4(QY8SHNJ;9iC`eFH_8+*KAqGlpzcAXqB+RR-Bo#%p}U2RhGFk{3cqB>Sj8nG zY=S&y&zm+Z#Hf=in_OEjXVPFZHu@!^+>}8c(?J*^#Kmp!*dRJW>{P$?2Pqj|?n1Yq z42u5~P+_@FxV%7=wd#q9mpT>MR~NaGK6q0u3}Oleq#23IW7{_X&!@r%h~2KL@%s=h z_rxdHZ7U>`AEkUTLT%4&EfjGLQ^KZw9UQ_BO@l1$L+H){ak?|d@qvXiOz$8kJM1N1 zR`7Yu>FDuG7Kv&*BF4*FNF5)9f9W)*mklLf!@W}qIpRhvM`K~>J9v;hgGgjm{K6$x9_&c-J$uXZk_4b_l%hB&3`HJKY3J`5&OKKaE{SYZM)o>LhG)qSc1 zI@--~Ep2^=PUfdks1cIq6&k|1Gv4w^FFzT5X<*P=X8OQJKfiRD;OXd0oAG^$JZLeN zDOvknBG(jDYd&lYuz#YI0d#JX*VW%Ya@?vk?zuet+0dAiW;hb^b|pz zgt)UINM}@yNvsyN;m2Y$3x`4FC6I|YV5F_JSrs{O{8cHA$k)}~B-*jN{bCIDZP@q*1xrj0G#=Wki=8%!Ae?#Jksz3jWoY)Tk=xQlhuXV|{` z6VRHd>HCY`yzqTWVh;tLrSy}`dnbQq$A%DrP{wl+q+iFwDD4` zVEXw@%>paE2bR|PV={2#Yv1W)_m3$kg}@<7Uui;t5F}{ON(F@$-iB3we%L-uh)?F5 zh+UyhQmYBm-N&GC46ON8HsEFDw^pdA`6>~Rp=Rw+mRyKlQ}~u*Z~GtCe!pkD$PIgW zM3GCQhe}EW^^Uo6T|`5aMDP- z*}#x=ZZ^4zfRMc`>weF~07|(6S&*v(YdNc`XulDG$OQvZLgjWd6p&;CJ!C$QuHLW) z5Fd`q`@U|5D>O)v-&r1!_~K0jg}Sx3%>lp>Q%B>WItuuG-zs1{Sa@D7L&jnTNO3Ob zho_Kf83DM*jo+gk`=4j_h$Y;+(?i(2#Fnw&kld1GHg(s6?LTY)zEKqE$s$xf9s|Bn zRDac?^2XEIS3+k)h}^b~4M4Yk^}3>mg5hXi_O^~a1}ho~)g~5Y5j}$c`uoZHz5{Dj zj|s*=Yvlr@Q&dC@v{n;(_F2SkDn?MS&av?_t+Ll!FN<#jI2oLkU+p z54galoximH$6_@H9;&MH7q3N3 zlKKX#v7i5u-tTfiT>VZwd<{wOO+cnOK7qZDKgjFe#PKum+ z36Uv)Oun!O@edE_+r7Ebl;Yhed%b=#-@9KIswzworTG52^80nLvM{A7sEhSC@&@RY zlK61f^2vX=edqwkYN-<-Q(KoS*dOl{eQiTx=?|P80F6FxA`~$F zP96cD-dBh__#e37P+0HUT}BMCjmDsy^74Ww(Qjj7v{!kCg75K^=g^#@ul(}^BH$Jc zJCmRQ;JVq7{ss$oK&=HZIi}{Re>hX zOI`Z3B7w_8O8>~fBan@4vNa_^AgBhSIu*oK5|pcb13p!;J9QMwNkK|>Xvbx{Qt|aN z5o^f=?D>Ok%wbL{u3VtJ=EeWpJM(faWQMP)W=*?Q$1ri4c7i71G{K@1o?UK4csa{I z`Zh*K)rG}HC`JE?j;cR37NLi8N&t|H?iV4jfuw&|dco>G<-Mn;>FhS< znmRohPEK!<>&R~!^uMYM1Sac?misS?$@zl~ zp1*iY59)QSI|!PIYkSZABZdFjD!_GpI*@;OCj&A2Hxe9B8uj*wzrt_df*u0>*(-s~ z^9k>~4Q-wk1X7tTLbm=Ja&SfwxO7|=Y0#(t%Q7B;6*fIkBS9I1-^e%MQx)^WN1^Tf zFUvS}0!Vfh$3+MvG;V+&y!tJVbpr!Fa)BrOC@SOX-w^Wqe}2Qi-^l+R4*$K3S5JV1 z9Wra#4vEwW@Pm7q+BG+>@qI)WILG|G|Kiwxneayd{s_STwbA^80RK{=KM3$2NA`~i z_+tY8_yB)=fIm*)A1Cln6tM0m{D}hogn@s;z(09_KY4&ZiJ;%}KYxePzh!=YBmX3V z{$v9Gm%_-OOyIu~n}1Tle^SAJY5{+00e^}?e~LjHZq=V^;Gb&XpK|b@a`2yifIs~J ze;PvQHt|nGh~n`jAE#y%)_!MeXD6yRN1j>QIoIr@LQv04_(N?aFu=G_Nh{&GG zw_n&Gg-SuC{2R`memLORSD=3vT~KKITlL`I9Y*g!)2{we zl>fie02>X<=fLgtf8_KX-n6I@-~mTvJ7sAkDA_FA&{mb_Do zty5+7-qG686Ah+`Xg3c?)MA~!6<24en)*Fo>V-EJ_2z29uNUIgvh17dOeA#_y&UFR`* z2Mfv|CjRHkba`8qXn3ry<^e+sQmt8ds2<)aRS*Ez@DQM}P@Dk&7^g=H#*y&Yn|u^`5vsj4E9GtWjb$Zkv(> z9)9I+jgZkVY<@DKV#SK(P1G({_$eQIZl^n`(ZnV9S?NZh$2+!S4{}{hgJ!G_Ov(fI zgINj&$r~?FLY)ea3q&uy+s22tM=+k;^Via4jG6dOfH(MkhGLpP7R)Y1QEY;IoLbTr zVw36^qqMf?n{$FQX;+N@0IMf!o@ z@>1dpB~}bgU-c>^9Qbd^S9q8V2)y6o8?!z2>-Q_q{(|c&!TypnE@S8%Eo_jQG}Eb& z*#E-EX|ZKG3YaQ|KWRgTl)q-jQ|aNgvXjdy{a*dH1&Munm|vk9{qCby z?ho!pSVSgM%~GS6r=!(owPHPysfam|Ayt&DUB1g_Y2%Vwf7gdnQ(I+kpt_HF8m1cL zTHQ`Pd*HZ`62q#j@!H_8HN(82H_9w^fy_wN&jtj_DfbThpb-xKa(Lewwrt{dN`8A* zlPc9&ADm$yvn;MI@dEy9#hBigBs;DJpodX9)IYR>(_)O0?e(wJMB zyU1vIWkyVvzf%x{eXc?7f!W=@L_gPRpW4TxL0ryf9=+<1w`X{J?v8YD;J4wB@##zC zl$2<2u;tOmCkrSA8vTT9x5U0I#kGhqAE%>g(2-a^724qGg)GhWiEkhzIDv+t37lQu zleMViBgewf=>K~AYtLgL!d%<7Vh!DPW^taRRJEHW6K<+e|+9A01ou^OR(1i2-H~t{^ zZT+{I2x`SARczo#cScpu01nY;Eu(^sB)hNg^@e}QXFA~xN2D)^yM*_!-U z8-K6_6T3PUMI#0`-2f=@3Oya^tFf6#OIY9ZYM%$c#dBbIp1C_rAUd~4>HPpZxx{9! zyQ#1ky25@13ah7@1r&C0U123wfWj8JTm#o%y0vLfYe0bHu~yr|22H#%ZKzJE@>K8^ z-t@(zR1TZt)}u8qc|+6B=OMkmPolv91<&c?%U(0 z?rq{YDLpE8Z3|LVpcKALRZYOxjj)a~rx!Q(CA z6&z2kIdeZ`1=l$20|wR_n-g_{KK}Xh>j&aJ76-f2><)IF+TjnkV*MQpG#IvfvV7io z5}aZ%V=G-2u*KJf5g_#i>~P3~t=O)E2f?*MoAD`y6aOP!Mo%_Xa2yWK<)lvOpf$m-@0|u5sQwsf+0G|YO_eKWVMXSr;&DVu;fvJ z6jyla8K9>+3}zge$BMRI+<8*$zGk=_lkaVw#mbA_5*D+eRz~hiF)6M!VaQmky>E|a zi`$NUBZ^CRs`M>k<6Ot^e8AM`Ba}nX*FMD*pQT%>P)|zg8d+P++6*JRhhO*28CUq| zj+A`o+tg^6W-%}RMz;hLCEmUCBjV`F=5^*#c7K8!!`m}-W&3)St3Fc3;o(nNays@? zpGEKhth1@aGY_fA;-Dg*y6GNqSOZSva2s+$Hew%rloF}KKP>fJ`gZL0-OjKUeGa7q zDR7FUp~*ha_Y0R9zR{(O06jwtdz{_M@a;IzGr?j4Bk z#$ql^~qn)zJ9%Yfa3w(B<4Rj5e(#fWH1o0 z&dnzM2o$zN07yxYu_Mq6%O!*&c%_#?LXF74gjof&3f7;|ywLZ!`#?Gs=I-y`O0 zt*Il}<+n2cn_6r0e4KdP4R88X2<--52jjs2uARGZa>noIUPo`Jzc|3pXKt`VfXO*I z<{N-nVM&jrCJJ?|A@JTxw~3|Z)$>Z&EzZEECsD=DX1#2FmT(sk|DkaV27o8sD8 zS9*I^urNz};lmV4cC{nx>a2-s19^xCO^FdweHcY~aXKX*yA>H}<%XU*pW;fg{#j0* zk6k;_*k0b^!E-JP=OSz6&6CP`f#lLN(2ki81P&%2dgVw;J_SK|XN4xWV%28{SX5O| zA+)(94Q2n^++jEQyoY-<$n}!rv$sT+?rI|zke{^B(?#|-P%w%xkHy2Jsmi2&sT1#r zm{G#jl8dfhReox-7`;J>PR+qrwbPNb`H_o59$149RztMGRB%(_V}92oWrb~~m3YK? zfg{`+IWdZ`vbr5XC`SGukF|};eweUc&UNtXpdq+R;Hk4{Vy@aOO~w*;N6%})1@L5u z6jF+ga#`Nh=0$Uoe~GZ1P5UKGnv+&xrbOpid-0r8-QNhmtKELr)|uN+-6-Fnudp;Z zQK$HPdcdgHd>l+UOP0VXmZV#9b*U_`p&dt_su)u4wv)pOi$Cm+O};Jth{&QgJFPd3 zz}OVEADlvk2@HvLX!1*ngXPv)+bN+){!RTlq*Oa=*?t}P;JMg`jE*XIyHK8nt<4hG zXKi`rkBAk+WonV+(=b&%m)ZVh6%y>tKE23bE!v!5&-WV zWnC8#pAx$@n=|V7bvE~@rFmmSJyhTQr^XV7l=LPEd= zxH}h7totc24$cpxnmy~Bcw#4dCz@7|_Fpn0cV8UpwU?FcEMH9PK}MKF`wP3nQXTol zJh<5FsKMhd`)f$CJ;srXYrYmS(N>bQ<4CRSZarC+iTWX~C&|w;9r5w*(q=uHcPc!3 z6sky2pqW7TX{S$GQXo+F01lDN=?{$Jif^XFo{smLqs0$9*s-pg-)`qYn2g!5jpbGU z_s7+G>-=}0yyti0fi!8)$$Ro1WjlY>dG3>XCzb@fZvEvLN$#?puj|rq&t6|fv+oh7 zJ(SzIoUj1=D8)4eTJHD0Ov#Wd(Z|)MQhx}kfq&mkbxfB=CqA3b*W9M{Af~uqXChl7HkxCY$#%* zH2q+Mc5Y-!(rF$==!fsjJ-UUh9b#1-4+tYIHE}@elT?j&$83*0lA!vhW`KyrZ{kNylvQZ-5oVO7hZ% zBayV-k6WD0&+?2RI5Y~}#KHrsK7`s&ST`9%~t zCFCAU%`$ns0j_?OhN=0)GRa*Ut05%?C^GT=L1>tRtu?Y#3Lml4!n_Bwx04lpdKgzc(6##~6Ta?82!A;;umK@NeB`^T^ z9lhJ7m&T@xQsS>&AslCni?y!YX!OUKakvnddEcrzqq4*x_XC~ zqFrGIi|s{lTLsT_xxQ}m#{jw*E^HsOo4zqEuiY~5EX?|5IcIPeNPmjeT$DkP>$smDb&C|%6tC<$ zuA18MCQD9{NNVP$DP{ zGION5+*eAGdIwsQu4n6nuTwEVwT}3=jH(#4KI;}vaO%gfvDBF!cwDk_%4e%#r8Oi}sRtI_+K_IujqW*PY5Bj>BO1!2$Hd~DU! zbLmsZmZXaKyGGOAV+wYX1pWJh)u@myGxchk8aK@ zVbs=x?}mLGhn}~wn)mc*R(nr+Z#PgYP0n&! zm(~)!W>~|^E-6Ry9HLlFkq}`*u z?O!IwZqjKUaV@R()2F_|ab6qDP<^^%ooI7)wP{9@#}Sn`#wdO|C$H`)(2?J{EVf?N zCE_rhT57SSBiVyW`NH-{vz(CX*{Axp4=3ES3l`cD#d%Y_U*E*6;z+1lXen#WG^Qq7 zkJNL_r&RlajK^;R<9-9(I#q3J>aKD6n)5i5YHUnRwF-xRyhmAd<`08TdO_$)LWbGG4Hw2?I&_30yWFXRR%M>Fs`<-3Soi831 zpw$sY9AV4E9E=e4#$Jv@<LYclpUPY+B#szat8 zq__IKtIs`|p#Rtt4<-y4ZA7Xlp(k5M3ohV2cQkoQ0apl1@%$PRr7Jb6zzT4 zmz{qUjQ-uNoEIWfBC*c1_EXt&aN?Zx*p6N$d)<`b?bTXEvs#o#MT|)>k$lBPF%AI){k!*j(y)cs~YiBgX4LMuACTOEj8O zK2s)N1?o4{OL7tAxgOD|amMrZC)!}%mzi^MpoUu))G&f45mEDBA{6EFB?RZB!o!lK zXHXkL`fKI6mgS7pi($WU zHd9$_ox;rfh;9)OJ73bo&JjSh$dH&S1Ca(kRW7vO3AVv4t2S1s?zU3cGMVrwYyEE$ zBaJ$n)3#QPNZ&VZP5O8qHKW)TLIG1Df=CGo4nW7To^Ht)pB@sdL-)0R1vyOM%s5i& zzdrKfu)EH39P!hsUo{Ips_rel*#5>bYH{5I1jSxc5{46kbvgW(QIusk=^wX~saTjX zrJ}zV%vi#L8Cyr$VCx6c8Ihvlrj+7~%_|N`=G?3Vr3>hB*VKbYdelGMlz#P zX@1xI{@T5;-bG6)hh7~f<8Nk8uey?2*Jk=>g5&i$9erErVNgvF7HKU=+r{~fyDbHw zp_2}6Fn|&y=Z!?G)IT{Pt_Mo$SIS{TKT2X0cGg~PpK#IFDwBT*(VRJW>~yX1Awfc0 z!u|T)xWa)z>-eT?jp-4o9f!;1jEJy~}L zz^==e1bL?B30c^(WQQnzF{ZmgtD)xjna> zBF+SRITlYh`BLIt=BS2_B}D5OBbp0%PKqV^@G0jTE<~_W;U3dB)u^49gwZ;s@&o#F!3%(rfRLLoC zOk~p9SnKDz73YVbD-+kh%wVEEf1!274y4mj27Y1^ad*3YbYrx{#+&Rq z#~$SM#vYqfA*o;{QE6TS#{LOTNd|*}bzHWYVKvt!d?Yov4W%day2bI-?R4m0a0ZS% zT+`k~F*WUwi#2Z1b@qy1tB+A6&K4V(&poC+>o{N)Ip5rv@0#X6mK?z_{Pfk|#eano zCZUD0HsT#UXV;;+()3RQ)VAfQJ%v{5hKMfcU9oLr)sv_K0Xxo35MVt#UMVWJyb0`2^{Vu4QTXg3l z*ht=qZwKC<>09^Pu=L|LmHWahqGvugz)U zYMkn$k);pL&THL#0LLacj3hx2tZ4*hHg~wD9w1VC%B(+x1wrN}X#o0A-?sl^eo`lX z>8_C*JF6>Xw%i?++7Q*Vq=OTWn3*5Zw=WtX=H~nwt7&2PL#xrDXppIgQ&M?j@fi#r zYeta+$ge=@tQ_!ti?5h(=GlVC`K#*>e~{tTLUe%hVc2fJ{3WW{chnY90uDeJ6*NHQ z)%1eHO>#@2+0BAY<|oVKU$6S!O9*C)Qq74$nRv|OgMMvmEeTeksPx)6{m0UqgXyBE z48TLkkP+JYna9eVtK?Eep5^}$fOcOGQQGwor43PoFtKt+{*`apb(XuA#dbPt+ZmP> z&|g#f&H4Y$pduj!bM>6FML~67!DX>az*_Hx#&2(iF){iDe(tHHz{m0Mab)C8u%et0E2@NKK8WA?TH;@4 zWL}Pxeueu3&qZKu?cQt(c7jaaf}JocDh`BzN<@N#zEg02 zpReXZxh}Pa+5|25b%n}gHS+P5c5^-INU2qr6Ls~y5@ExTzU*R!$}5j5JxuMuTo_7> z0Gme2i9Wt{5rus|Zw+r2A0o5pnCr4o!dtxI&xKhON&7#VMQ;I1z?#}(Yw!VRibs8A z6!;A5VQqpgR|Z{94slKY6f{NK>*Oyrv;7G8nZXUGx5n=ljAIX2ui}fZf zE*Et#VZ63amh^2-pGeS{?UrQk9JG|J|6JB$8uRw)+K6YvYNADGJf}ZNEX+w!X}U2n zkHg7_ah)QQgp)fyYgooQsg~Gk;k8_5!HjJ7>4|k>&9oeWK*s(AA!^fWWy4n8PlG## zZtart^}%!4xZ*t|rXoE(G0(fN5`f-LbyG7O zGjo{rI4}B*XyIX5zuu;np4-Rbqn*SQzHLlomN?HLl$ZvzjwZoHWxUEj@k_Q?O2<5z z^1?uI;OB(Z1Z5#VV-V9-Yrm+NIe9V@k6P8w=w6>WZyHL{XOv7Sv6r=lwcCqjdC$ez zrP}W)nXY8|G}h3MspfYL{fYPt5t6uXh!0`vBcgPyfJq7V_i}c?w0)pipDznOoGGdD;>f2mJ!r4>8qu|z$7nj!2tc7M(&7ZMl$ooRapQ^K8lieE$Lxcl@ za^fxB436pzFU-Bht=G*uWezT)tj&jG96zyBQ#GT_RDji6WO~5!PwH=_xbq^M} z4ZW(==r6w509LysSnVyUsn7Gt)FpLALBhEHPs#v}bx+VrwFnggVa^+u%!}k)KGDyr zL1pPb&K%|#nG9_IQdxof*=XzrE5E4qA?+s%qN~1wBke)Yfw|db;})E|eiIa1(9`BkXu&&-Wsws}NUu0&{0$jpHA%SzRm z=qB}R+ZlgM73i|es$2HpwoLE8w?6Zl4W8W32~O@fNx>axF*5EBu6neKg))#2sg`Mx z506m_sXjWR7_KQ)tCZI@^sS}Q*3J7Wp2%vLQk-4ZQ@p?SSWOUGxF7w(+RO@yVQ*bK z!Yc`R_d3Kt{Ko?R_|3&X>t|tOn_=u!B9Z8iXMt;t-|k z1X>FOX4#P=YXO99@tn&!gAEEmUrk?LP@O|+FqC#T97x+%C_$HDIS6M`sj6CGo&et4 zUh23P2m@=k-|LpY*(-JcO4Q0RJMRRbOaDOek8J!CRCJ>nuRyqX15(R;{VM3? z(%2x>xOZ_~pv^__;yj*nU0EZy#B`@#{G_GqRg%B5cZLi?a=YN5 z((K)Da=(qR4dM(HH&2ye!}Z|jBJ~DH%}>Kg5Uh}Bnq$pQ8Ski?MIsk6oQO}*mOl(K zV_*W}{Q=453`(=i7EuNcGWcbO_d&;)OZc8o1pKw-Tv@?Iy@K;r@l?h|qN1FJIf9!o zN_{hhk1BvT30hV>%pTWC3EvBfPS*-%?*o|kJ?mGitzQn>ybr7JeSW^0Me#lGV0~9N+42@Pe04=gd%vlUJ~CA zYiEEZX}=w+?}G3AlgA25nJ!HrVL2-?dy*?5H@L@dOJ}ca1BeJ4u^$%b12YJFVdq}b zb#!v5vm79Nja8z;oIFd6$Wy4IXKkzG_CCC|4{S>71#62@2kW_WByAJCHgIf382vWD zXD>t=w^BB?#l6z$7;W?KjW#fUBtaFxbhy$c-?39^n?S1t+MI>)d3_x{391hkU85TO z2}V-r9&-qR6n-4rN(1NILr;Vkm0FL)@IEUB)bdXFDuftbo!#QPjgOX>r@_#;kOBQ_ znV%>?eE@PqoiY48ElTsUe#S~Y#5BL+2sYH-hbGULKB#(hU2xYbxyl`pUjfV8?#H!I z3~5~eUlHS-es;iUd#FE^|E40QP4HtX?gX&0mxsQ~GHJYp5OA(1KmrbR4 zx?iJm)kVE|(iPN^LGu)(bRe5OvtTc*!%*4`;kzxd~uCuLk%B z*6h0@p;O2_GL^^4P zFtVWI7cEBi-(N&Qh1F|(%GkSvig&n_`}og9q~%@fPt|itT6<;Pj@p)MJN!L}WVBU6 z__y%uqG3)6%3fIpisO&wrAV8|?2l<)RU5Ok2pX=r5-mmR>BCk+cG#~?k&l;u4=Fmu&0>Bh=)(DqMYoOqr;3kZDSN#)3jeyY@GA#>I9}bc(+ANn@j4F?k#!rdqrQd zD*kiJ0O*+dWbFUYNwzCGbgWja@OUle%L5@z0!ySA_uO)V9HUlLbh`WI=PlRA@-BIe zt)1{`EJ;mJoB^HRoLP&}MtRTfwU3YIn9gYSv>VSlUhLB_I-sA0YXdv-O@cC5G71cV zv`wmvreJGAMR$#xk-VV};&tH7L zrhId6Z)}eZo|dd$@}tV8bPDzCitjo2&g11pQzfATBRxGH4OqqMqxjB_`f=2>^VkCx z0i{}BrBGW5W9Hf!oSa(QbX$q_iIvjfkEy44`-nx>C-^ryl*!Y2Iwk#l%<`LARTP4o zFKX6utXZ~&{hPKW%j$Wo@tWz_r!U;&xD)}#$`0}ycCmiKjt##BHEUwugjwnK9e zcovN_A~}u^*fclYe(&lhS%k-u#cj=@tG0QM|EvireHi5&rGjsAP6w@jbJ*S`%}~{C zg`cZsxT*4jK2HCxkBd-~BZk;Di2od=tQ6woU82IO5-yRhp;OH#Xp`1Aqbe#CYtGfq zDGiYK)@awC>zdckN&sl3U^G{%PCMcjNf~uaGD{?U#FB`Tr81%&+nK-za^gbfcB1A= z%!Zc6-Ic&g5mVXe&&-(W=v8Gkot@MLDXa3W_%WY*_y@@HU2+aayaP8(Oh7)RaBQxD zb9rph>ox%fupXpZ1>}NvL?Zb4^|>!O)5-Q0-l;~us{7Hbt*4z-{(Rh)u>g$bnFV!;m$MKy`tL0#Wc=-29)GcB5=n>ihSS4w_}ykWz4`o1Ek5tGN+q<(CQb z4Lu{C&8V!Xa8C%_Zz%|x+2332&J6z^3|MXGxq8>Z!_eLmk5r@wQsaIq&Tm zn)S~c(l++!RCN(=K8P0D+3$&7L6M8+n(+;@n{SMb$S#e&9`+x+)C6=WbEMH(8t2OL z2IkIpt7Da%&|}N*bB354JgwE&mOjC*3z^CM^O#nCh|e@jpBg3wO7-Lr#Tz0f_4~TV z^+8x4G=P~+{3^)MjCqKdcJiq0YtBLE96P?x7=RJKj!m`K3#-6nTq)fRCrDj& z{`R?J3S|uFh`eBVZ>9L5EH5A%oc~w!L;f2b7*9HYv7mSAMgpo7pS=0qjR5)!{P!tB z;w)f;f+IXRNFdcS4uR`^2tM0{-`!h$ej=QgrEwQIOyzaR3o4H%vV0FhDphtZ-tRJF zCE|Vt@5h|A(RV3dD|?Q>K6J2A9rq z6w9}0&o+dr6&*K9Ju4d|?KsfsW)bC7I!hHh#=3;hyW5JD3Oib>a#0%R%1DSue2OI`uNzR23D#v$AsgHkhjg?%%{yJ62LRGcj8f zf@%eaYg9J<+FRUMZWp0?Y zeVr*l&@AymBR=5CF%<2Z{Bcat_V57u&CZlWxzSn7v+v&9UOmZD^HkFmnG)8av}+aW zE1q>^)qmPcLd^s^>t)pW=t_^8C=5|TGKn`2PZ!1bc1%8yTBB7~P~qeF#&v>|+s10j z7Nz#+pub^egcHo{68vI|JF^fsHKc5{*;-&PKK1F6oWygvvqIB&ssh}$Cdn9r$ zLz2&Wj?>oF8Pe{g#@Q($1hbC4p=O&91>y_}qz^%65e4D_3gqP#VltT!zS~$dzI9|H z#qSuY1GkgHy1iob%BgEqd8zsYSi9xU;?ZN6R!`+X-2ZWzHbkW`=(xIKM`ev)*#fxvo+8Y@8|t=D;{_ho%Nf!dObQo~Z0V6A0MbZq{tyrAq1 zhYo`q75ZHm4J*u>J}Z6-Q8vLjqw+JJK;)U8AtcH7H8ensh5Y7Mix8}o za+XMAHR7961L${0MO0UC?7x79VL@2!C)4{y4#CocPeJg!guYh3I}S$jd5HRkGBdUp z{^IT`m0WlT9_9J*xSp_kye-I2q)Unho2_J`GtM5)Mndck3n6xPj!~KX*lo`_HQzX3 zH?-x=@9;Miy$%TH&&C%Efvk4xncjzaTV9_;+Wzj|gJSd;%@NnOH2sS(}z`j3>KPQaPz&n$7M!Zo40Frm1rA|?4Q%p;+6)lG=c56o*s z&yvUe&7v94Ec+5J(b_1r*e}2` zQI1n|$;U*GgEc40^`-D$&kvVeK5ia%;Sv(MZ&(Q3)9o_?&|Mp08Y%(#IJUvaZ8j1_ zpG}XC1w^KA$)77-TG9 zia!NH3gizNLn1JKioY3O{7YA<@M2Ee*Q z1ccg1oQ?x@#Q0@Y8>C3}Js0LJ(6YOr!tUMx-v2@#IKm#6PV|n|LYV4yZ9fB_Fp|9= z8vJT3p_c6OYFtrrwOp{Z`ThG?q_q%n0TuhNja@`x>fuK~5TGK??E=E1>1p`6O<2$K zVJ|b@C4op_WVR`blj8ZH$}y@MGj$m+ zsra?YV1|MBEy?LCInd<0cl4L}i|SFIrR!Dq)UXm{GgebQr8l|EO-;6#XI=BdyD+=A z*TG(~`NdtuUC_pRn5_C|TT=NWHEvW_?X?j)9VWuw`ZmuVM&c6a^|z;aK-HeJ7d`=I zhw2&7S(^Fr%?EX7SDn5*5_!xh%|*{qM~lpvzZ~yW${{h*jA+@u-t8@MqSH+V7UOlZ z$(2GqB?oI+H-#vw&ZTyZ50Cd`x)qC)n8npTYE;|cQbmAl3k}^btX9m(E+IWRKCNBt0rVEI-*S%gRie9b{;l zreI}8;JkJ6oZRn6Y7egRRm&06su78ml^Fdzo}X1)S#gr(kBdw_&QutDcz(vS$Yys< zqpeM!NRvSKx3NAo>KHf((3D<*5(oy&kB-c8%^=Aw}^ML7n>_H zD4OjBI@nXU{LauTKlOh0i4{fpG-a}LWS?I$HU(m2OCF6P{+M0tI5X0&fM!tF4S0LLqY zi@g!Hi@oay+K|3Jo1i$#sB3SlITt(m^tEUzHLhHZBeLSve0J9g8nZR(ef^x$i0zTl z$!SWdKeHg}R(;PWS4I1Hk(T-amHMi!GXAI|&uc~T{&f2aFU_9#)^E8HvnnK1o1N

                                  ~PUn|A-+CaJoF&~&upG-I5T*$$Y8 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 QTC(J*vfAO4gT`0>2W(SkHvj+t literal 0 HcmV?d00001 diff --git a/lessons/project-showcase/game.png b/lessons/project-showcase/game.png new file mode 100644 index 0000000000000000000000000000000000000000..65acfa66c56b664b9bf95e9d1a985dbb4652a34c GIT binary patch literal 185899 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

                                  Q*_e}N16S} zN&tLQKrJ9Qi*5-WNTS|e9!bnjNu?3;s8mroKnyjW$tXO8p%_uaSv{*&@z1^nj0YNnM4u^^L*86O4}X4GP~nwC^orbT9?- zbPl@WXCPA!2K8B!KsJZySduxyBP6t#OlIL-8jx@#k@ObVsVJLV5sfNg|9Q)baeN7kJ4`o;?*zIUH3{CjfaYo5+Hcb?(SNGBy*0vI>-xqPH*eY01O! zyw+tI{e(J~!J#H1o#O~eGC1gqmC4;lL3QFl4Wdy)X&i~4v5S)wk)5R5WUxZ>Mcp+u zKGvR|l$APA@AaS^Io2wxJrp?Op?fY4x#SV{IYkV!bCWTXm9^>c9!CDJ$N`;@uti+aI4W^PL;BKqS0^LB1LS4*9;~SS$TW6#Pp)WO zcJP1yLs;)24HjO7$f-`AAPYVl_&su_Qkp9E#);v66T|%?pIg>%(JAKk#bn5ZI2lOv zShNhy7hPM8*?u%g@d`ka_Zrv*T?!R|YvE-BtZ;d2I7)tZQ1}sig)i`=fz|%SXUa_@ zUIIAe*A`2eN=-T@z?}(jXWTt9-!@u^cHYddg%JNuzC_g3U;8TZAa!B=?F5=2uMUMC z1|d|hyPV&S^rl-sACk#>-P2vE1xR<4&<`yQ7{Md`3&FLRjjGt50k3*hLlr$lYAD`u zwMvsXx|53F`-!$JmAvQ)5>MF;;>e*mZw{2j$VAP-9?v0W^UV0-xVuc@7BmrI|mdB2NZL z&)Qxgb&Noyj;hpHMiJk(4QiqjRe6%7SEcCN)``keNWLq6hQtQ(!SJLdCn2^NfJF7z zdRCxYn63zfu5i6zX0VQ-Jf@?}i$I+ac^y>2C?O=; zE3=+p+6!+ol){_LQ{hdPi+GbIBi>}BrkCDi$|?hSv?f@a(m`&T+KDHSf!$O^8=oTI zf6cn*o%@IBQ|YTzfy_YD`)lqw8;&kCJGgZERaHP?peCMph0{=pa^3N3*lP@T6)28X2&4%wR zS9>mRwLU-LY&Fi*^Q&y(MWCOsF?*|Q%)nGfHrfH92~^z(QUoF=1fxdEG^AM$!GVz8 zxgi-50jU+8a%gT_Q8+VAMic0A!L_QX7hUUUfrzDUMyaml4dY|gtOY4c2;9O(F8LwFMeu1BxVrzh^cC^EaNkpcw#MB z_>7*AW-Gewin2waE^y@Rh$n;M1& literal 0 HcmV?d00001 diff --git a/lessons/project-showcase/graph_vis_demo.mkv b/lessons/project-showcase/graph_vis_demo.mkv new file mode 100644 index 0000000000000000000000000000000000000000..a2f08eb5d3b1f3c52d0497173ca57e6ac517b97a GIT binary patch literal 8726688 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

                                  PiIaZjx98=*SBX%lu#rr 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%0AOHve0)PM@00;mAfB+x>2mk_r03ZMe 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

                                  A1{pAk&zYvJ09)t4_-X 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