···11+# This file is automatically @generated by Cargo.
22+# It is not intended for manual editing.
33+version = 4
44+55+[[package]]
66+name = "exercises"
77+version = "0.0.0"
+222
Cargo.toml
···11+bin = [
22+ { name = "intro1", path = "exercises/00_intro/intro1.rs" },
33+ { name = "intro1_sol", path = "solutions/00_intro/intro1.rs" },
44+ { name = "intro2", path = "exercises/00_intro/intro2.rs" },
55+ { name = "intro2_sol", path = "solutions/00_intro/intro2.rs" },
66+ { name = "variables1", path = "exercises/01_variables/variables1.rs" },
77+ { name = "variables1_sol", path = "solutions/01_variables/variables1.rs" },
88+ { name = "variables2", path = "exercises/01_variables/variables2.rs" },
99+ { name = "variables2_sol", path = "solutions/01_variables/variables2.rs" },
1010+ { name = "variables3", path = "exercises/01_variables/variables3.rs" },
1111+ { name = "variables3_sol", path = "solutions/01_variables/variables3.rs" },
1212+ { name = "variables4", path = "exercises/01_variables/variables4.rs" },
1313+ { name = "variables4_sol", path = "solutions/01_variables/variables4.rs" },
1414+ { name = "variables5", path = "exercises/01_variables/variables5.rs" },
1515+ { name = "variables5_sol", path = "solutions/01_variables/variables5.rs" },
1616+ { name = "variables6", path = "exercises/01_variables/variables6.rs" },
1717+ { name = "variables6_sol", path = "solutions/01_variables/variables6.rs" },
1818+ { name = "functions1", path = "exercises/02_functions/functions1.rs" },
1919+ { name = "functions1_sol", path = "solutions/02_functions/functions1.rs" },
2020+ { name = "functions2", path = "exercises/02_functions/functions2.rs" },
2121+ { name = "functions2_sol", path = "solutions/02_functions/functions2.rs" },
2222+ { name = "functions3", path = "exercises/02_functions/functions3.rs" },
2323+ { name = "functions3_sol", path = "solutions/02_functions/functions3.rs" },
2424+ { name = "functions4", path = "exercises/02_functions/functions4.rs" },
2525+ { name = "functions4_sol", path = "solutions/02_functions/functions4.rs" },
2626+ { name = "functions5", path = "exercises/02_functions/functions5.rs" },
2727+ { name = "functions5_sol", path = "solutions/02_functions/functions5.rs" },
2828+ { name = "if1", path = "exercises/03_if/if1.rs" },
2929+ { name = "if1_sol", path = "solutions/03_if/if1.rs" },
3030+ { name = "if2", path = "exercises/03_if/if2.rs" },
3131+ { name = "if2_sol", path = "solutions/03_if/if2.rs" },
3232+ { name = "if3", path = "exercises/03_if/if3.rs" },
3333+ { name = "if3_sol", path = "solutions/03_if/if3.rs" },
3434+ { name = "quiz1", path = "exercises/quizzes/quiz1.rs" },
3535+ { name = "quiz1_sol", path = "solutions/quizzes/quiz1.rs" },
3636+ { name = "primitive_types1", path = "exercises/04_primitive_types/primitive_types1.rs" },
3737+ { name = "primitive_types1_sol", path = "solutions/04_primitive_types/primitive_types1.rs" },
3838+ { name = "primitive_types2", path = "exercises/04_primitive_types/primitive_types2.rs" },
3939+ { name = "primitive_types2_sol", path = "solutions/04_primitive_types/primitive_types2.rs" },
4040+ { name = "primitive_types3", path = "exercises/04_primitive_types/primitive_types3.rs" },
4141+ { name = "primitive_types3_sol", path = "solutions/04_primitive_types/primitive_types3.rs" },
4242+ { name = "primitive_types4", path = "exercises/04_primitive_types/primitive_types4.rs" },
4343+ { name = "primitive_types4_sol", path = "solutions/04_primitive_types/primitive_types4.rs" },
4444+ { name = "primitive_types5", path = "exercises/04_primitive_types/primitive_types5.rs" },
4545+ { name = "primitive_types5_sol", path = "solutions/04_primitive_types/primitive_types5.rs" },
4646+ { name = "primitive_types6", path = "exercises/04_primitive_types/primitive_types6.rs" },
4747+ { name = "primitive_types6_sol", path = "solutions/04_primitive_types/primitive_types6.rs" },
4848+ { name = "vecs1", path = "exercises/05_vecs/vecs1.rs" },
4949+ { name = "vecs1_sol", path = "solutions/05_vecs/vecs1.rs" },
5050+ { name = "vecs2", path = "exercises/05_vecs/vecs2.rs" },
5151+ { name = "vecs2_sol", path = "solutions/05_vecs/vecs2.rs" },
5252+ { name = "move_semantics1", path = "exercises/06_move_semantics/move_semantics1.rs" },
5353+ { name = "move_semantics1_sol", path = "solutions/06_move_semantics/move_semantics1.rs" },
5454+ { name = "move_semantics2", path = "exercises/06_move_semantics/move_semantics2.rs" },
5555+ { name = "move_semantics2_sol", path = "solutions/06_move_semantics/move_semantics2.rs" },
5656+ { name = "move_semantics3", path = "exercises/06_move_semantics/move_semantics3.rs" },
5757+ { name = "move_semantics3_sol", path = "solutions/06_move_semantics/move_semantics3.rs" },
5858+ { name = "move_semantics4", path = "exercises/06_move_semantics/move_semantics4.rs" },
5959+ { name = "move_semantics4_sol", path = "solutions/06_move_semantics/move_semantics4.rs" },
6060+ { name = "move_semantics5", path = "exercises/06_move_semantics/move_semantics5.rs" },
6161+ { name = "move_semantics5_sol", path = "solutions/06_move_semantics/move_semantics5.rs" },
6262+ { name = "structs1", path = "exercises/07_structs/structs1.rs" },
6363+ { name = "structs1_sol", path = "solutions/07_structs/structs1.rs" },
6464+ { name = "structs2", path = "exercises/07_structs/structs2.rs" },
6565+ { name = "structs2_sol", path = "solutions/07_structs/structs2.rs" },
6666+ { name = "structs3", path = "exercises/07_structs/structs3.rs" },
6767+ { name = "structs3_sol", path = "solutions/07_structs/structs3.rs" },
6868+ { name = "enums1", path = "exercises/08_enums/enums1.rs" },
6969+ { name = "enums1_sol", path = "solutions/08_enums/enums1.rs" },
7070+ { name = "enums2", path = "exercises/08_enums/enums2.rs" },
7171+ { name = "enums2_sol", path = "solutions/08_enums/enums2.rs" },
7272+ { name = "enums3", path = "exercises/08_enums/enums3.rs" },
7373+ { name = "enums3_sol", path = "solutions/08_enums/enums3.rs" },
7474+ { name = "strings1", path = "exercises/09_strings/strings1.rs" },
7575+ { name = "strings1_sol", path = "solutions/09_strings/strings1.rs" },
7676+ { name = "strings2", path = "exercises/09_strings/strings2.rs" },
7777+ { name = "strings2_sol", path = "solutions/09_strings/strings2.rs" },
7878+ { name = "strings3", path = "exercises/09_strings/strings3.rs" },
7979+ { name = "strings3_sol", path = "solutions/09_strings/strings3.rs" },
8080+ { name = "strings4", path = "exercises/09_strings/strings4.rs" },
8181+ { name = "strings4_sol", path = "solutions/09_strings/strings4.rs" },
8282+ { name = "modules1", path = "exercises/10_modules/modules1.rs" },
8383+ { name = "modules1_sol", path = "solutions/10_modules/modules1.rs" },
8484+ { name = "modules2", path = "exercises/10_modules/modules2.rs" },
8585+ { name = "modules2_sol", path = "solutions/10_modules/modules2.rs" },
8686+ { name = "modules3", path = "exercises/10_modules/modules3.rs" },
8787+ { name = "modules3_sol", path = "solutions/10_modules/modules3.rs" },
8888+ { name = "hashmaps1", path = "exercises/11_hashmaps/hashmaps1.rs" },
8989+ { name = "hashmaps1_sol", path = "solutions/11_hashmaps/hashmaps1.rs" },
9090+ { name = "hashmaps2", path = "exercises/11_hashmaps/hashmaps2.rs" },
9191+ { name = "hashmaps2_sol", path = "solutions/11_hashmaps/hashmaps2.rs" },
9292+ { name = "hashmaps3", path = "exercises/11_hashmaps/hashmaps3.rs" },
9393+ { name = "hashmaps3_sol", path = "solutions/11_hashmaps/hashmaps3.rs" },
9494+ { name = "quiz2", path = "exercises/quizzes/quiz2.rs" },
9595+ { name = "quiz2_sol", path = "solutions/quizzes/quiz2.rs" },
9696+ { name = "options1", path = "exercises/12_options/options1.rs" },
9797+ { name = "options1_sol", path = "solutions/12_options/options1.rs" },
9898+ { name = "options2", path = "exercises/12_options/options2.rs" },
9999+ { name = "options2_sol", path = "solutions/12_options/options2.rs" },
100100+ { name = "options3", path = "exercises/12_options/options3.rs" },
101101+ { name = "options3_sol", path = "solutions/12_options/options3.rs" },
102102+ { name = "errors1", path = "exercises/13_error_handling/errors1.rs" },
103103+ { name = "errors1_sol", path = "solutions/13_error_handling/errors1.rs" },
104104+ { name = "errors2", path = "exercises/13_error_handling/errors2.rs" },
105105+ { name = "errors2_sol", path = "solutions/13_error_handling/errors2.rs" },
106106+ { name = "errors3", path = "exercises/13_error_handling/errors3.rs" },
107107+ { name = "errors3_sol", path = "solutions/13_error_handling/errors3.rs" },
108108+ { name = "errors4", path = "exercises/13_error_handling/errors4.rs" },
109109+ { name = "errors4_sol", path = "solutions/13_error_handling/errors4.rs" },
110110+ { name = "errors5", path = "exercises/13_error_handling/errors5.rs" },
111111+ { name = "errors5_sol", path = "solutions/13_error_handling/errors5.rs" },
112112+ { name = "errors6", path = "exercises/13_error_handling/errors6.rs" },
113113+ { name = "errors6_sol", path = "solutions/13_error_handling/errors6.rs" },
114114+ { name = "generics1", path = "exercises/14_generics/generics1.rs" },
115115+ { name = "generics1_sol", path = "solutions/14_generics/generics1.rs" },
116116+ { name = "generics2", path = "exercises/14_generics/generics2.rs" },
117117+ { name = "generics2_sol", path = "solutions/14_generics/generics2.rs" },
118118+ { name = "traits1", path = "exercises/15_traits/traits1.rs" },
119119+ { name = "traits1_sol", path = "solutions/15_traits/traits1.rs" },
120120+ { name = "traits2", path = "exercises/15_traits/traits2.rs" },
121121+ { name = "traits2_sol", path = "solutions/15_traits/traits2.rs" },
122122+ { name = "traits3", path = "exercises/15_traits/traits3.rs" },
123123+ { name = "traits3_sol", path = "solutions/15_traits/traits3.rs" },
124124+ { name = "traits4", path = "exercises/15_traits/traits4.rs" },
125125+ { name = "traits4_sol", path = "solutions/15_traits/traits4.rs" },
126126+ { name = "traits5", path = "exercises/15_traits/traits5.rs" },
127127+ { name = "traits5_sol", path = "solutions/15_traits/traits5.rs" },
128128+ { name = "quiz3", path = "exercises/quizzes/quiz3.rs" },
129129+ { name = "quiz3_sol", path = "solutions/quizzes/quiz3.rs" },
130130+ { name = "lifetimes1", path = "exercises/16_lifetimes/lifetimes1.rs" },
131131+ { name = "lifetimes1_sol", path = "solutions/16_lifetimes/lifetimes1.rs" },
132132+ { name = "lifetimes2", path = "exercises/16_lifetimes/lifetimes2.rs" },
133133+ { name = "lifetimes2_sol", path = "solutions/16_lifetimes/lifetimes2.rs" },
134134+ { name = "lifetimes3", path = "exercises/16_lifetimes/lifetimes3.rs" },
135135+ { name = "lifetimes3_sol", path = "solutions/16_lifetimes/lifetimes3.rs" },
136136+ { name = "tests1", path = "exercises/17_tests/tests1.rs" },
137137+ { name = "tests1_sol", path = "solutions/17_tests/tests1.rs" },
138138+ { name = "tests2", path = "exercises/17_tests/tests2.rs" },
139139+ { name = "tests2_sol", path = "solutions/17_tests/tests2.rs" },
140140+ { name = "tests3", path = "exercises/17_tests/tests3.rs" },
141141+ { name = "tests3_sol", path = "solutions/17_tests/tests3.rs" },
142142+ { name = "iterators1", path = "exercises/18_iterators/iterators1.rs" },
143143+ { name = "iterators1_sol", path = "solutions/18_iterators/iterators1.rs" },
144144+ { name = "iterators2", path = "exercises/18_iterators/iterators2.rs" },
145145+ { name = "iterators2_sol", path = "solutions/18_iterators/iterators2.rs" },
146146+ { name = "iterators3", path = "exercises/18_iterators/iterators3.rs" },
147147+ { name = "iterators3_sol", path = "solutions/18_iterators/iterators3.rs" },
148148+ { name = "iterators4", path = "exercises/18_iterators/iterators4.rs" },
149149+ { name = "iterators4_sol", path = "solutions/18_iterators/iterators4.rs" },
150150+ { name = "iterators5", path = "exercises/18_iterators/iterators5.rs" },
151151+ { name = "iterators5_sol", path = "solutions/18_iterators/iterators5.rs" },
152152+ { name = "box1", path = "exercises/19_smart_pointers/box1.rs" },
153153+ { name = "box1_sol", path = "solutions/19_smart_pointers/box1.rs" },
154154+ { name = "rc1", path = "exercises/19_smart_pointers/rc1.rs" },
155155+ { name = "rc1_sol", path = "solutions/19_smart_pointers/rc1.rs" },
156156+ { name = "arc1", path = "exercises/19_smart_pointers/arc1.rs" },
157157+ { name = "arc1_sol", path = "solutions/19_smart_pointers/arc1.rs" },
158158+ { name = "cow1", path = "exercises/19_smart_pointers/cow1.rs" },
159159+ { name = "cow1_sol", path = "solutions/19_smart_pointers/cow1.rs" },
160160+ { name = "threads1", path = "exercises/20_threads/threads1.rs" },
161161+ { name = "threads1_sol", path = "solutions/20_threads/threads1.rs" },
162162+ { name = "threads2", path = "exercises/20_threads/threads2.rs" },
163163+ { name = "threads2_sol", path = "solutions/20_threads/threads2.rs" },
164164+ { name = "threads3", path = "exercises/20_threads/threads3.rs" },
165165+ { name = "threads3_sol", path = "solutions/20_threads/threads3.rs" },
166166+ { name = "macros1", path = "exercises/21_macros/macros1.rs" },
167167+ { name = "macros1_sol", path = "solutions/21_macros/macros1.rs" },
168168+ { name = "macros2", path = "exercises/21_macros/macros2.rs" },
169169+ { name = "macros2_sol", path = "solutions/21_macros/macros2.rs" },
170170+ { name = "macros3", path = "exercises/21_macros/macros3.rs" },
171171+ { name = "macros3_sol", path = "solutions/21_macros/macros3.rs" },
172172+ { name = "macros4", path = "exercises/21_macros/macros4.rs" },
173173+ { name = "macros4_sol", path = "solutions/21_macros/macros4.rs" },
174174+ { name = "clippy1", path = "exercises/22_clippy/clippy1.rs" },
175175+ { name = "clippy1_sol", path = "solutions/22_clippy/clippy1.rs" },
176176+ { name = "clippy2", path = "exercises/22_clippy/clippy2.rs" },
177177+ { name = "clippy2_sol", path = "solutions/22_clippy/clippy2.rs" },
178178+ { name = "clippy3", path = "exercises/22_clippy/clippy3.rs" },
179179+ { name = "clippy3_sol", path = "solutions/22_clippy/clippy3.rs" },
180180+ { name = "using_as", path = "exercises/23_conversions/using_as.rs" },
181181+ { name = "using_as_sol", path = "solutions/23_conversions/using_as.rs" },
182182+ { name = "from_into", path = "exercises/23_conversions/from_into.rs" },
183183+ { name = "from_into_sol", path = "solutions/23_conversions/from_into.rs" },
184184+ { name = "from_str", path = "exercises/23_conversions/from_str.rs" },
185185+ { name = "from_str_sol", path = "solutions/23_conversions/from_str.rs" },
186186+ { name = "try_from_into", path = "exercises/23_conversions/try_from_into.rs" },
187187+ { name = "try_from_into_sol", path = "solutions/23_conversions/try_from_into.rs" },
188188+ { name = "as_ref_mut", path = "exercises/23_conversions/as_ref_mut.rs" },
189189+ { name = "as_ref_mut_sol", path = "solutions/23_conversions/as_ref_mut.rs" },
190190+]
191191+192192+[package]
193193+name = "exercises"
194194+edition = "2021"
195195+# Don't publish the exercises on crates.io!
196196+publish = false
197197+198198+[profile.release]
199199+panic = "abort"
200200+201201+[profile.dev]
202202+panic = "abort"
203203+204204+[lints.rust]
205205+# You shouldn't write unsafe code in Rustlings!
206206+unsafe_code = "forbid"
207207+# You don't need unstable features in Rustlings and shouldn't rely on them while learning Rust.
208208+unstable_features = "forbid"
209209+# Dead code warnings can't be avoided in some exercises and might distract while learning.
210210+dead_code = "allow"
211211+212212+[lints.clippy]
213213+# You forgot a `todo!()`!
214214+todo = "forbid"
215215+# This can only happen by mistake in Rustlings.
216216+empty_loop = "forbid"
217217+# No infinite loops are needed in Rustlings.
218218+infinite_loop = "deny"
219219+# You shouldn't leak memory while still learning Rust!
220220+mem_forget = "deny"
221221+# Currently, there are no disallowed methods. This line avoids problems when developing Rustlings.
222222+disallowed_methods = "allow"
···11+# Intro
22+33+Rust uses the `print!` and `println!` macros to print text to the console.
44+55+## Further information
66+77+- [Hello World](https://doc.rust-lang.org/rust-by-example/hello.html)
88+- [Formatted print](https://doc.rust-lang.org/rust-by-example/hello/print.html)
+24
exercises/00_intro/intro1.rs
···11+// TODO: We sometimes encourage you to keep trying things on a given exercise
22+// even after you already figured it out. If you got everything working and feel
33+// ready for the next exercise, enter `n` in the terminal.
44+//
55+// The exercise file will be reloaded when you change one of the lines below!
66+// Try adding a new `println!` and check the updated output in the terminal.
77+88+fn main() {
99+ println!(r#" Welcome to... "#);
1010+ println!(r#" _ _ _ "#);
1111+ println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
1212+ println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
1313+ println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
1414+ println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
1515+ println!(r#" |___/ "#);
1616+ println!();
1717+ println!("This exercise compiles successfully. The remaining exercises contain a compiler");
1818+ println!("or logic error. The central concept behind Rustlings is to fix these errors and");
1919+ println!("solve the exercises. Good luck!");
2020+ println!();
2121+ println!("The file of this exercise is `exercises/00_intro/intro1.rs`. Have a look!");
2222+ println!("The current exercise path will be always shown under the progress bar.");
2323+ println!("You can click on the path to open the exercise file in your editor.");
2424+}
+4
exercises/00_intro/intro2.rs
···11+fn main() {
22+ // TODO: Fix the code to print "Hello world!".
33+ println!("Hello world!");
44+}
+9
exercises/01_variables/README.md
···11+# Variables
22+33+In Rust, variables are immutable by default.
44+When a variable is immutable, once a value is bound to a name, you can’t change that value.
55+You can make them mutable by adding `mut` in front of the variable name.
66+77+## Further information
88+99+- [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html)
+6
exercises/01_variables/variables1.rs
···11+fn main() {
22+ // TODO: Add the missing keyword.
33+ let x = 5;
44+55+ println!("x has the value {x}");
66+}
+10
exercises/01_variables/variables2.rs
···11+fn main() {
22+ // TODO: Change the line below to fix the compiler error.
33+ let x = 0;
44+55+ if x == 10 {
66+ println!("x is ten!");
77+ } else {
88+ println!("x is not ten!");
99+ }
1010+}
+6
exercises/01_variables/variables3.rs
···11+fn main() {
22+ // TODO: Change the line below to fix the compiler error.
33+ let x: i32 = 0;
44+55+ println!("Number {x}");
66+}
+8
exercises/01_variables/variables4.rs
···11+// TODO: Fix the compiler error.
22+fn main() {
33+ let mut x = 3;
44+ println!("Number {x}");
55+66+ x = 5; // Don't change this line
77+ println!("Number {x}");
88+}
+8
exercises/01_variables/variables5.rs
···11+fn main() {
22+ let number = "T-H-R-E-E"; // Don't change this line
33+ println!("Spell a number: {}", number);
44+55+ // TODO: Fix the compiler error by changing the line below without renaming the variable.
66+ let number = 3;
77+ println!("Number plus two is: {}", number + 2);
88+}
+6
exercises/01_variables/variables6.rs
···11+// TODO: Change the line below to fix the compiler error.
22+const NUMBER: i32 = 3;
33+44+fn main() {
55+ println!("Number: {NUMBER}");
66+}
+8
exercises/02_functions/README.md
···11+# Functions
22+33+Here, you'll learn how to write functions and how the Rust compiler can help you debug errors even
44+in more complex code.
55+66+## Further information
77+88+- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
+7
exercises/02_functions/functions1.rs
···11+// TODO: Add some function with the name `call_me` without arguments or a return value.
22+33+fn call_me() {}
44+55+fn main() {
66+ call_me(); // Don't change this line
77+}
+10
exercises/02_functions/functions2.rs
···11+// TODO: Add the missing type of the argument `num` after the colon `:`.
22+fn call_me(num: i32) {
33+ for i in 0..num {
44+ println!("Ring! Call number {}", i + 1);
55+ }
66+}
77+88+fn main() {
99+ call_me(3);
1010+}
+10
exercises/02_functions/functions3.rs
···11+fn call_me(num: u8) {
22+ for i in 0..num {
33+ println!("Ring! Call number {}", i + 1);
44+ }
55+}
66+77+fn main() {
88+ // TODO: Fix the function call.
99+ call_me(3);
1010+}
+22
exercises/02_functions/functions4.rs
···11+// This store is having a sale where if the price is an even number, you get 10
22+// Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
33+// Don't worry about the function bodies themselves, we are only interested in
44+// the signatures for now.
55+66+fn is_even(num: i64) -> bool {
77+ num % 2 == 0
88+}
99+1010+// TODO: Fix the function signature.
1111+fn sale_price(price: i64) -> i64 {
1212+ if is_even(price) {
1313+ price - 10
1414+ } else {
1515+ price - 3
1616+ }
1717+}
1818+1919+fn main() {
2020+ let original_price = 51;
2121+ println!("Your sale price is {}", sale_price(original_price));
2222+}
+9
exercises/02_functions/functions5.rs
···11+// TODO: Fix the function body without changing the signature.
22+fn square(num: i32) -> i32 {
33+ num * num
44+}
55+66+fn main() {
77+ let answer = square(3);
88+ println!("The square of 3 is {answer}");
99+}
+7
exercises/03_if/README.md
···11+# If
22+33+`if`, the most basic (but still surprisingly versatile!) type of control flow, is what you'll learn here.
44+55+## Further information
66+77+- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions)
+37
exercises/03_if/if1.rs
···11+fn bigger(a: i32, b: i32) -> i32 {
22+ // TODO: Complete this function to return the bigger number!
33+ // If both numbers are equal, any of them can be returned.
44+ // Do not use:
55+ // - another function call
66+ // - additional variables
77+ if a > b {
88+ a
99+ } else {
1010+ b
1111+ }
1212+}
1313+1414+fn main() {
1515+ // You can optionally experiment here.
1616+}
1717+1818+// Don't mind this for now :)
1919+#[cfg(test)]
2020+mod tests {
2121+ use super::*;
2222+2323+ #[test]
2424+ fn ten_is_bigger_than_eight() {
2525+ assert_eq!(10, bigger(10, 8));
2626+ }
2727+2828+ #[test]
2929+ fn fortytwo_is_bigger_than_thirtytwo() {
3030+ assert_eq!(42, bigger(32, 42));
3131+ }
3232+3333+ #[test]
3434+ fn equal_numbers() {
3535+ assert_eq!(42, bigger(42, 42));
3636+ }
3737+}
+39
exercises/03_if/if2.rs
···11+// TODO: Fix the compiler error on this function.
22+fn picky_eater(food: &str) -> &str {
33+ if food == "strawberry" {
44+ "Yummy!"
55+ } else if food == "potato" {
66+ "I guess I can eat that."
77+ } else {
88+ "No thanks!"
99+ }
1010+}
1111+1212+fn main() {
1313+ // You can optionally experiment here.
1414+}
1515+1616+// TODO: Read the tests to understand the desired behavior.
1717+// Make all tests pass without changing them.
1818+#[cfg(test)]
1919+mod tests {
2020+ use super::*;
2121+2222+ #[test]
2323+ fn yummy_food() {
2424+ // This means that calling `picky_eater` with the argument "food" should return "Yummy!".
2525+ assert_eq!(picky_eater("strawberry"), "Yummy!");
2626+ }
2727+2828+ #[test]
2929+ fn neutral_food() {
3030+ assert_eq!(picky_eater("potato"), "I guess I can eat that.");
3131+ }
3232+3333+ #[test]
3434+ fn default_disliked_food() {
3535+ assert_eq!(picky_eater("broccoli"), "No thanks!");
3636+ assert_eq!(picky_eater("gummy bears"), "No thanks!");
3737+ assert_eq!(picky_eater("literally anything"), "No thanks!");
3838+ }
3939+}
···11+# Primitive Types
22+33+Rust has a couple of basic types that are directly implemented into the
44+compiler. In this section, we'll go through the most important ones.
55+66+## Further information
77+88+- [Data Types](https://doc.rust-lang.org/book/ch03-02-data-types.html)
99+- [The Slice Type](https://doc.rust-lang.org/book/ch04-03-slices.html)
+16
exercises/04_primitive_types/primitive_types1.rs
···11+// Booleans (`bool`)
22+33+fn main() {
44+ let is_morning = true;
55+ if is_morning {
66+ println!("Good morning!");
77+ }
88+99+ // TODO: Define a boolean variable with the name `is_evening` before the `if` statement below.
1010+ // The value of the variable should be the negation (opposite) of `is_morning`.
1111+ // let …
1212+ let is_evening = !is_morning;
1313+ if is_evening {
1414+ println!("Good evening!");
1515+ }
1616+}
+28
exercises/04_primitive_types/primitive_types2.rs
···11+// Characters (`char`)
22+33+fn main() {
44+ // Note the _single_ quotes, these are different from the double quotes
55+ // you've been seeing around.
66+ let my_first_initial = 'C';
77+ if my_first_initial.is_alphabetic() {
88+ println!("Alphabetical!");
99+ } else if my_first_initial.is_numeric() {
1010+ println!("Numerical!");
1111+ } else {
1212+ println!("Neither alphabetic nor numeric!");
1313+ }
1414+1515+ // TODO: Analogous to the example before, declare a variable called `your_character`
1616+ // below with your favorite character.
1717+ // Try a letter, try a digit (in single quotes), try a special character, try a character
1818+ // from a different language than your own, try an emoji 😉
1919+ let your_character = 'c';
2020+2121+ if your_character.is_alphabetic() {
2222+ println!("Alphabetical!");
2323+ } else if your_character.is_numeric() {
2424+ println!("Numerical!");
2525+ } else {
2626+ println!("Neither alphabetic nor numeric!");
2727+ }
2828+}
+11
exercises/04_primitive_types/primitive_types3.rs
···11+fn main() {
22+ // TODO: Create an array called `a` with at least 100 elements in it.
33+ let a: [i32; 100] = [0; 100];
44+55+ if a.len() >= 100 {
66+ println!("Wow, that's a big array!");
77+ } else {
88+ println!("Meh, I eat arrays like that for breakfast.");
99+ panic!("Array not big enough, more elements needed");
1010+ }
1111+}
+17
exercises/04_primitive_types/primitive_types4.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ #[test]
88+ fn slice_out_of_array() {
99+ let a = [1, 2, 3, 4, 5];
1010+1111+ // TODO: Get a slice called `nice_slice` out of the array `a` so that the test passes.
1212+ // let nice_slice = ???
1313+ let nice_slice = &a[1..4];
1414+1515+ assert_eq!([2, 3, 4], nice_slice);
1616+ }
1717+}
+9
exercises/04_primitive_types/primitive_types5.rs
···11+fn main() {
22+ let cat = ("Furry McFurson", 3.5);
33+44+ // TODO: Destructure the `cat` tuple in one statement so that the println works.
55+ // let /* your pattern here */ = cat;
66+ let (name, age) = cat;
77+88+ println!("{name} is {age} years old");
99+}
+18
exercises/04_primitive_types/primitive_types6.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ #[test]
88+ fn indexing_tuple() {
99+ let numbers = (1, 2, 3);
1010+1111+ // TODO: Use a tuple index to access the second element of `numbers`
1212+ // and assign it to a variable called `second`.
1313+ // let second = ???;
1414+ let second = numbers.1;
1515+1616+ assert_eq!(second, 2, "This is not the 2nd number in the tuple!");
1717+ }
1818+}
+17
exercises/05_vecs/README.md
···11+# Vectors
22+33+Vectors are one of the most-used Rust data structures. In other programming
44+languages, they'd simply be called Arrays, but since Rust operates on a
55+bit of a lower level, an array in Rust is stored on the stack (meaning it
66+can't grow or shrink, and the size needs to be known at compile time),
77+and a Vector is stored in the heap (where these restrictions do not apply).
88+99+Vectors are a bit of a later chapter in the book, but we think that they're
1010+useful enough to talk about them a bit earlier. We shall be talking about
1111+the other useful data structure, hash maps, later.
1212+1313+## Further information
1414+1515+- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/book/ch08-01-vectors.html)
1616+- [`iter_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.iter_mut)
1717+- [`map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map)
+25
exercises/05_vecs/vecs1.rs
···11+fn array_and_vec() -> ([i32; 4], Vec<i32>) {
22+ let a = [10, 20, 30, 40]; // Array
33+44+ // TODO: Create a vector called `v` which contains the exact same elements as in the array `a`.
55+ // Use the vector macro.
66+ // let v = ???;
77+ let v = vec![10, 20, 30, 40];
88+99+ (a, v)
1010+}
1111+1212+fn main() {
1313+ // You can optionally experiment here.
1414+}
1515+1616+#[cfg(test)]
1717+mod tests {
1818+ use super::*;
1919+2020+ #[test]
2121+ fn test_array_and_vec_similarity() {
2222+ let (a, v) = array_and_vec();
2323+ assert_eq!(a, *v);
2424+ }
2525+}
+56
exercises/05_vecs/vecs2.rs
···11+fn vec_loop(input: &[i32]) -> Vec<i32> {
22+ let mut output = Vec::new();
33+44+ for element in input {
55+ // TODO: Multiply each element in the `input` slice by 2 and push it to
66+ // the `output` vector.
77+ output.push(element * 2);
88+ }
99+1010+ output
1111+}
1212+1313+fn vec_map_example(input: &[i32]) -> Vec<i32> {
1414+ // An example of collecting a vector after mapping.
1515+ // We map each element of the `input` slice to its value plus 1.
1616+ // If the input is `[1, 2, 3]`, the output is `[2, 3, 4]`.
1717+ input.iter().map(|element| element + 1).collect()
1818+}
1919+2020+fn vec_map(input: &[i32]) -> Vec<i32> {
2121+ // TODO: Here, we also want to multiply each element in the `input` slice
2222+ // by 2, but with iterator mapping instead of manually pushing into an empty
2323+ // vector.
2424+ // See the example in the function `vec_map_example` above.
2525+ input.iter().map(|element| element * 2).collect()
2626+}
2727+2828+fn main() {
2929+ // You can optionally experiment here.
3030+}
3131+3232+#[cfg(test)]
3333+mod tests {
3434+ use super::*;
3535+3636+ #[test]
3737+ fn test_vec_loop() {
3838+ let input = [2, 4, 6, 8, 10];
3939+ let ans = vec_loop(&input);
4040+ assert_eq!(ans, [4, 8, 12, 16, 20]);
4141+ }
4242+4343+ #[test]
4444+ fn test_vec_map_example() {
4545+ let input = [1, 2, 3];
4646+ let ans = vec_map_example(&input);
4747+ assert_eq!(ans, [2, 3, 4]);
4848+ }
4949+5050+ #[test]
5151+ fn test_vec_map() {
5252+ let input = [2, 4, 6, 8, 10];
5353+ let ans = vec_map(&input);
5454+ assert_eq!(ans, [4, 8, 12, 16, 20]);
5555+ }
5656+}
+10
exercises/06_move_semantics/README.md
···11+# Move Semantics
22+33+These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!
44+55+## Further information
66+77+For this section, the book links are especially important.
88+99+- [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
1010+- [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)
+24
exercises/06_move_semantics/move_semantics1.rs
···11+// TODO: Fix the compiler error in this function.
22+fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
33+ let mut vec = vec;
44+55+ vec.push(88);
66+77+ vec
88+}
99+1010+fn main() {
1111+ // You can optionally experiment here.
1212+}
1313+1414+#[cfg(test)]
1515+mod tests {
1616+ use super::*;
1717+1818+ #[test]
1919+ fn move_semantics1() {
2020+ let vec0 = vec![22, 44, 66];
2121+ let vec1 = fill_vec(vec0);
2222+ assert_eq!(vec1, vec![22, 44, 66, 88]);
2323+ }
2424+}
+28
exercises/06_move_semantics/move_semantics2.rs
···11+fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
22+ let mut vec = vec;
33+44+ vec.push(88);
55+66+ vec
77+}
88+99+fn main() {
1010+ // You can optionally experiment here.
1111+}
1212+1313+#[cfg(test)]
1414+mod tests {
1515+ use super::*;
1616+1717+ // TODO: Make both vectors `vec0` and `vec1` accessible at the same time to
1818+ // fix the compiler error in the test.
1919+ #[test]
2020+ fn move_semantics2() {
2121+ let vec0 = vec![22, 44, 66];
2222+2323+ let vec1 = fill_vec(vec0.clone());
2424+2525+ assert_eq!(vec0, [22, 44, 66]);
2626+ assert_eq!(vec1, [22, 44, 66, 88]);
2727+ }
2828+}
+22
exercises/06_move_semantics/move_semantics3.rs
···11+// TODO: Fix the compiler error in the function without adding any new line.
22+fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> {
33+ vec.push(88);
44+55+ vec
66+}
77+88+fn main() {
99+ // You can optionally experiment here.
1010+}
1111+1212+#[cfg(test)]
1313+mod tests {
1414+ use super::*;
1515+1616+ #[test]
1717+ fn move_semantics3() {
1818+ let vec0 = vec![22, 44, 66];
1919+ let vec1 = fill_vec(vec0);
2020+ assert_eq!(vec1, [22, 44, 66, 88]);
2121+ }
2222+}
+18
exercises/06_move_semantics/move_semantics4.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ // TODO: Fix the compiler errors only by reordering the lines in the test.
88+ // Don't add, change or remove any line.
99+ #[test]
1010+ fn move_semantics4() {
1111+ let mut x = Vec::new();
1212+ let y = &mut x;
1313+ y.push(42);
1414+ let z = &mut x;
1515+ z.push(13);
1616+ assert_eq!(x, [42, 13]);
1717+ }
1818+}
+24
exercises/06_move_semantics/move_semantics5.rs
···11+#![allow(clippy::ptr_arg)]
22+33+// TODO: Fix the compiler errors without changing anything except adding or
44+// removing references (the character `&`).
55+66+// Shouldn't take ownership
77+fn get_char(data: &String) -> char {
88+ data.chars().last().unwrap()
99+}
1010+1111+// Should take ownership
1212+fn string_uppercase(mut data: String) {
1313+ data = data.to_uppercase();
1414+1515+ println!("{data}");
1616+}
1717+1818+fn main() {
1919+ let data = "Rust is great!".to_string();
2020+2121+ get_char(&data);
2222+2323+ string_uppercase(data);
2424+}
+8
exercises/07_structs/README.md
···11+# Structs
22+33+Rust has three struct types: a classic C struct, a tuple struct, and a unit struct.
44+55+## Further information
66+77+- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
88+- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
+56
exercises/07_structs/structs1.rs
···11+struct ColorRegularStruct {
22+ // TODO: Add the fields that the test `regular_structs` expects.
33+ // What types should the fields have? What are the minimum and maximum values for RGB colors?
44+ red: i32,
55+ green: i32,
66+ blue: i32,
77+}
88+99+// struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */);
1010+struct ColorTupleStruct(i32, i32, i32);
1111+1212+#[derive(Debug)]
1313+struct UnitStruct;
1414+1515+fn main() {
1616+ // You can optionally experiment here.
1717+}
1818+1919+#[cfg(test)]
2020+mod tests {
2121+ use super::*;
2222+2323+ #[test]
2424+ fn regular_structs() {
2525+ // TODO: Instantiate a regular struct.
2626+ // let green =
2727+ let green = ColorRegularStruct {
2828+ red: 0,
2929+ green: 255,
3030+ blue: 0,
3131+ };
3232+3333+ assert_eq!(green.red, 0);
3434+ assert_eq!(green.green, 255);
3535+ assert_eq!(green.blue, 0);
3636+ }
3737+3838+ #[test]
3939+ fn tuple_structs() {
4040+ // TODO: Instantiate a tuple struct.
4141+ let green = ColorTupleStruct(0, 255, 0);
4242+4343+ assert_eq!(green.0, 0);
4444+ assert_eq!(green.1, 255);
4545+ assert_eq!(green.2, 0);
4646+ }
4747+4848+ #[test]
4949+ fn unit_structs() {
5050+ // TODO: Instantiate a unit struct.
5151+ let unit_struct = UnitStruct;
5252+ let message = format!("{unit_struct:?}s are fun!");
5353+5454+ assert_eq!(message, "UnitStructs are fun!");
5555+ }
5656+}
+52
exercises/07_structs/structs2.rs
···11+#[derive(Debug)]
22+struct Order {
33+ name: String,
44+ year: u32,
55+ made_by_phone: bool,
66+ made_by_mobile: bool,
77+ made_by_email: bool,
88+ item_number: u32,
99+ count: u32,
1010+}
1111+1212+fn create_order_template() -> Order {
1313+ Order {
1414+ name: String::from("Bob"),
1515+ year: 2019,
1616+ made_by_phone: false,
1717+ made_by_mobile: false,
1818+ made_by_email: true,
1919+ item_number: 123,
2020+ count: 0,
2121+ }
2222+}
2323+2424+fn main() {
2525+ // You can optionally experiment here.
2626+}
2727+2828+#[cfg(test)]
2929+mod tests {
3030+ use super::*;
3131+3232+ #[test]
3333+ fn your_order() {
3434+ let order_template = create_order_template();
3535+3636+ // TODO: Create your own order using the update syntax and template above!
3737+ // let your_order =
3838+ let your_order = Order {
3939+ name: "Hacker in Rust".to_string(),
4040+ count: 1,
4141+ ..order_template
4242+ };
4343+4444+ assert_eq!(your_order.name, "Hacker in Rust");
4545+ assert_eq!(your_order.year, order_template.year);
4646+ assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
4747+ assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
4848+ assert_eq!(your_order.made_by_email, order_template.made_by_email);
4949+ assert_eq!(your_order.item_number, order_template.item_number);
5050+ assert_eq!(your_order.count, 1);
5151+ }
5252+}
+89
exercises/07_structs/structs3.rs
···11+// Structs contain data, but can also have logic. In this exercise, we have
22+// defined the `Package` struct, and we want to test some logic attached to it.
33+44+#[derive(Debug)]
55+struct Package {
66+ sender_country: String,
77+ recipient_country: String,
88+ weight_in_grams: u32,
99+}
1010+1111+impl Package {
1212+ fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
1313+ if weight_in_grams < 10 {
1414+ // This isn't how you should handle errors in Rust, but we will
1515+ // learn about error handling later.
1616+ panic!("Can't ship a package with weight below 10 grams");
1717+ }
1818+1919+ Self {
2020+ sender_country,
2121+ recipient_country,
2222+ weight_in_grams,
2323+ }
2424+ }
2525+2626+ // TODO: Add the correct return type to the function signature.
2727+ fn is_international(&self) -> bool {
2828+ // TODO: Read the tests that use this method to find out when a package
2929+ // is considered international.
3030+ self.sender_country != self.recipient_country
3131+ }
3232+3333+ // TODO: Add the correct return type to the function signature.
3434+ fn get_fees(&self, cents_per_gram: u32) -> u32 {
3535+ // TODO: Calculate the package's fees.
3636+ self.weight_in_grams * cents_per_gram
3737+ }
3838+}
3939+4040+fn main() {
4141+ // You can optionally experiment here.
4242+}
4343+4444+#[cfg(test)]
4545+mod tests {
4646+ use super::*;
4747+4848+ #[test]
4949+ #[should_panic]
5050+ fn fail_creating_weightless_package() {
5151+ let sender_country = String::from("Spain");
5252+ let recipient_country = String::from("Austria");
5353+5454+ Package::new(sender_country, recipient_country, 5);
5555+ }
5656+5757+ #[test]
5858+ fn create_international_package() {
5959+ let sender_country = String::from("Spain");
6060+ let recipient_country = String::from("Russia");
6161+6262+ let package = Package::new(sender_country, recipient_country, 1200);
6363+6464+ assert!(package.is_international());
6565+ }
6666+6767+ #[test]
6868+ fn create_local_package() {
6969+ let sender_country = String::from("Canada");
7070+ let recipient_country = sender_country.clone();
7171+7272+ let package = Package::new(sender_country, recipient_country, 1200);
7373+7474+ assert!(!package.is_international());
7575+ }
7676+7777+ #[test]
7878+ fn calculate_transport_fees() {
7979+ let sender_country = String::from("Spain");
8080+ let recipient_country = String::from("Spain");
8181+8282+ let cents_per_gram = 3;
8383+8484+ let package = Package::new(sender_country, recipient_country, 1500);
8585+8686+ assert_eq!(package.get_fees(cents_per_gram), 4500);
8787+ assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
8888+ }
8989+}
+10
exercises/08_enums/README.md
···11+# Enums
22+33+Rust allows you to define types called "enums" which enumerate possible values.
44+Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
55+Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
66+77+## Further information
88+99+- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
1010+- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
+17
exercises/08_enums/enums1.rs
···11+#[derive(Debug)]
22+enum Message {
33+ // TODO: Define a few types of messages as used below.
44+ Resize,
55+ Move,
66+ Echo,
77+ ChangeColor,
88+ Quit,
99+}
1010+1111+fn main() {
1212+ println!("{:?}", Message::Resize);
1313+ println!("{:?}", Message::Move);
1414+ println!("{:?}", Message::Echo);
1515+ println!("{:?}", Message::ChangeColor);
1616+ println!("{:?}", Message::Quit);
1717+}
···11+# Strings
22+33+Rust has two string types, a string slice (`&str`) and an owned string (`String`).
44+We're not going to dictate when you should use which one, but we'll show you how
55+to identify and create them, as well as use them.
66+77+## Further information
88+99+- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)
+9
exercises/09_strings/strings1.rs
···11+// TODO: Fix the compiler error without changing the function signature.
22+fn current_favorite_color() -> String {
33+ "blue".to_string()
44+}
55+66+fn main() {
77+ let answer = current_favorite_color();
88+ println!("My current favorite color is {answer}");
99+}
+14
exercises/09_strings/strings2.rs
···11+// TODO: Fix the compiler error in the `main` function without changing this function.
22+fn is_a_color_word(attempt: &str) -> bool {
33+ attempt == "green" || attempt == "blue" || attempt == "red"
44+}
55+66+fn main() {
77+ let word = String::from("green"); // Don't change this line.
88+99+ if is_a_color_word(&word) {
1010+ println!("That is a color word I know!");
1111+ } else {
1212+ println!("That is not a color word I know.");
1313+ }
1414+}
+48
exercises/09_strings/strings3.rs
···11+fn trim_me(input: &str) -> &str {
22+ // TODO: Remove whitespace from both ends of a string.
33+ input.trim()
44+}
55+66+fn compose_me(input: &str) -> String {
77+ // TODO: Add " world!" to the string! There are multiple ways to do this.
88+ format!("{input} world!")
99+}
1010+1111+fn replace_me(input: &str) -> String {
1212+ // TODO: Replace "cars" in the string with "balloons".
1313+ input.replace("cars", "balloons")
1414+}
1515+1616+fn main() {
1717+ // You can optionally experiment here.
1818+}
1919+2020+#[cfg(test)]
2121+mod tests {
2222+ use super::*;
2323+2424+ #[test]
2525+ fn trim_a_string() {
2626+ assert_eq!(trim_me("Hello! "), "Hello!");
2727+ assert_eq!(trim_me(" What's up!"), "What's up!");
2828+ assert_eq!(trim_me(" Hola! "), "Hola!");
2929+ }
3030+3131+ #[test]
3232+ fn compose_a_string() {
3333+ assert_eq!(compose_me("Hello"), "Hello world!");
3434+ assert_eq!(compose_me("Goodbye"), "Goodbye world!");
3535+ }
3636+3737+ #[test]
3838+ fn replace_a_string() {
3939+ assert_eq!(
4040+ replace_me("I think cars are cool"),
4141+ "I think balloons are cool",
4242+ );
4343+ assert_eq!(
4444+ replace_me("I love to look at cars"),
4545+ "I love to look at balloons",
4646+ );
4747+ }
4848+}
+37
exercises/09_strings/strings4.rs
···11+// Calls of this function should be replaced with calls of `string_slice` or `string`.
22+fn placeholder() {}
33+44+fn string_slice(arg: &str) {
55+ println!("{arg}");
66+}
77+88+fn string(arg: String) {
99+ println!("{arg}");
1010+}
1111+1212+// TODO: Here are a bunch of values - some are `String`, some are `&str`.
1313+// Your task is to replace `placeholder(…)` with either `string_slice(…)`
1414+// or `string(…)` depending on what you think each value is.
1515+fn main() {
1616+ string_slice("blue");
1717+1818+ string("red".to_string());
1919+2020+ string(String::from("hi"));
2121+2222+ string("rust is fun!".to_owned());
2323+2424+ string("nice weather".into());
2525+2626+ string(format!("Interpolation {}", "Station"));
2727+2828+ // WARNING: This is byte indexing, not character indexing.
2929+ // Character indexing can be done using `s.chars().nth(INDEX)`.
3030+ string_slice(&String::from("abc")[0..1]);
3131+3232+ string_slice(" hello there ".trim());
3333+3434+ string("Happy Monday!".replace("Mon", "Tues"));
3535+3636+ string("mY sHiFt KeY iS sTiCkY".to_lowercase());
3737+}
+7
exercises/10_modules/README.md
···11+# Modules
22+33+In this section we'll give you an introduction to Rust's module system.
44+55+## Further information
66+77+- [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
+16
exercises/10_modules/modules1.rs
···11+// TODO: Fix the compiler error about calling a private function.
22+mod sausage_factory {
33+ // Don't let anybody outside of this module see this!
44+ fn get_secret_recipe() -> String {
55+ String::from("Ginger")
66+ }
77+88+ pub fn make_sausage() {
99+ get_secret_recipe();
1010+ println!("sausage!");
1111+ }
1212+}
1313+1414+fn main() {
1515+ sausage_factory::make_sausage();
1616+}
+28
exercises/10_modules/modules2.rs
···11+// You can bring module paths into scopes and provide new names for them with
22+// the `use` and `as` keywords.
33+44+mod delicious_snacks {
55+ // TODO: Add the following two `use` statements after fixing them.
66+ // use self::fruits::PEAR as ???;
77+ // use self::veggies::CUCUMBER as ???;
88+ pub use self::fruits::PEAR as fruit;
99+ pub use self::veggies::CUCUMBER as veggie;
1010+1111+ mod fruits {
1212+ pub const PEAR: &str = "Pear";
1313+ pub const APPLE: &str = "Apple";
1414+ }
1515+1616+ mod veggies {
1717+ pub const CUCUMBER: &str = "Cucumber";
1818+ pub const CARROT: &str = "Carrot";
1919+ }
2020+}
2121+2222+fn main() {
2323+ println!(
2424+ "favorite snacks: {} and {}",
2525+ delicious_snacks::fruit,
2626+ delicious_snacks::veggie,
2727+ );
2828+}
+15
exercises/10_modules/modules3.rs
···11+// You can use the `use` keyword to bring module paths from modules from
22+// anywhere and especially from the standard library into your scope.
33+44+// TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into
55+// your scope. Bonus style points if you can do it with one line!
66+// use ???;
77+use std::time::SystemTime;
88+use std::time::UNIX_EPOCH;
99+1010+fn main() {
1111+ match SystemTime::now().duration_since(UNIX_EPOCH) {
1212+ Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
1313+ Err(_) => panic!("SystemTime before UNIX EPOCH!"),
1414+ }
1515+}
+12
exercises/11_hashmaps/README.md
···11+# Hashmaps
22+33+A *hash map* allows you to associate a value with a particular key.
44+You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
55+[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
66+77+This is the other data structure that we've been talking about before, when
88+talking about Vecs.
99+1010+## Further information
1111+1212+- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
+43
exercises/11_hashmaps/hashmaps1.rs
···11+// A basket of fruits in the form of a hash map needs to be defined. The key
22+// represents the name of the fruit and the value represents how many of that
33+// particular fruit is in the basket. You have to put at least 3 different
44+// types of fruits (e.g. apple, banana, mango) in the basket and the total count
55+// of all the fruits should be at least 5.
66+77+use std::collections::HashMap;
88+99+fn fruit_basket() -> HashMap<String, u32> {
1010+ // TODO: Declare the hash map.
1111+ // let mut basket =
1212+ let mut basket = HashMap::new();
1313+1414+ // Two bananas are already given for you :)
1515+ basket.insert(String::from("banana"), 2);
1616+1717+ // TODO: Put more fruits in your basket.
1818+ basket.insert(String::from("apple"), 2);
1919+ basket.insert(String::from("orange"), 2);
2020+2121+ basket
2222+}
2323+2424+fn main() {
2525+ // You can optionally experiment here.
2626+}
2727+2828+#[cfg(test)]
2929+mod tests {
3030+ use super::*;
3131+3232+ #[test]
3333+ fn at_least_three_types_of_fruits() {
3434+ let basket = fruit_basket();
3535+ assert!(basket.len() >= 3);
3636+ }
3737+3838+ #[test]
3939+ fn at_least_five_fruits() {
4040+ let basket = fruit_basket();
4141+ assert!(basket.values().sum::<u32>() >= 5);
4242+ }
4343+}
+98
exercises/11_hashmaps/hashmaps2.rs
···11+// We're collecting different fruits to bake a delicious fruit cake. For this,
22+// we have a basket, which we'll represent in the form of a hash map. The key
33+// represents the name of each fruit we collect and the value represents how
44+// many of that particular fruit we have collected. Three types of fruits -
55+// Apple (4), Mango (2) and Lychee (5) are already in the basket hash map. You
66+// must add fruit to the basket so that there is at least one of each kind and
77+// more than 11 in total - we have a lot of mouths to feed. You are not allowed
88+// to insert any more of the fruits that are already in the basket (Apple,
99+// Mango, and Lychee).
1010+1111+use std::collections::HashMap;
1212+1313+#[derive(Hash, PartialEq, Eq, Debug)]
1414+enum Fruit {
1515+ Apple,
1616+ Banana,
1717+ Mango,
1818+ Lychee,
1919+ Pineapple,
2020+}
2121+2222+fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
2323+ let fruit_kinds = [
2424+ Fruit::Apple,
2525+ Fruit::Banana,
2626+ Fruit::Mango,
2727+ Fruit::Lychee,
2828+ Fruit::Pineapple,
2929+ ];
3030+3131+ for fruit in fruit_kinds {
3232+ // TODO: Insert new fruits if they are not already present in the
3333+ // basket. Note that you are not allowed to put any type of fruit that's
3434+ // already present!
3535+ basket.entry(fruit).or_insert(2);
3636+ }
3737+}
3838+3939+fn main() {
4040+ // You can optionally experiment here.
4141+}
4242+4343+#[cfg(test)]
4444+mod tests {
4545+ use super::*;
4646+4747+ // Don't modify this function!
4848+ fn get_fruit_basket() -> HashMap<Fruit, u32> {
4949+ let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
5050+ HashMap::from_iter(content)
5151+ }
5252+5353+ #[test]
5454+ fn test_given_fruits_are_not_modified() {
5555+ let mut basket = get_fruit_basket();
5656+ fruit_basket(&mut basket);
5757+ assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
5858+ assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
5959+ assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
6060+ }
6161+6262+ #[test]
6363+ fn at_least_five_types_of_fruits() {
6464+ let mut basket = get_fruit_basket();
6565+ fruit_basket(&mut basket);
6666+ let count_fruit_kinds = basket.len();
6767+ assert!(count_fruit_kinds >= 5);
6868+ }
6969+7070+ #[test]
7171+ fn greater_than_eleven_fruits() {
7272+ let mut basket = get_fruit_basket();
7373+ fruit_basket(&mut basket);
7474+ let count = basket.values().sum::<u32>();
7575+ assert!(count > 11);
7676+ }
7777+7878+ #[test]
7979+ fn all_fruit_types_in_basket() {
8080+ let fruit_kinds = [
8181+ Fruit::Apple,
8282+ Fruit::Banana,
8383+ Fruit::Mango,
8484+ Fruit::Lychee,
8585+ Fruit::Pineapple,
8686+ ];
8787+8888+ let mut basket = get_fruit_basket();
8989+ fruit_basket(&mut basket);
9090+9191+ for fruit_kind in fruit_kinds {
9292+ let Some(amount) = basket.get(&fruit_kind) else {
9393+ panic!("Fruit kind {fruit_kind:?} was not found in basket");
9494+ };
9595+ assert!(*amount > 0);
9696+ }
9797+ }
9898+}
+101
exercises/11_hashmaps/hashmaps3.rs
···11+// A list of scores (one per line) of a soccer match is given. Each line is of
22+// the form "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>"
33+// Example: "England,France,4,2" (England scored 4 goals, France 2).
44+//
55+// You have to build a scores table containing the name of the team, the total
66+// number of goals the team scored, and the total number of goals the team
77+// conceded.
88+99+use std::collections::HashMap;
1010+1111+// A structure to store the goal details of a team.
1212+#[derive(Default)]
1313+struct TeamScores {
1414+ goals_scored: u8,
1515+ goals_conceded: u8,
1616+}
1717+1818+fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
1919+ // The name of the team is the key and its associated struct is the value.
2020+ let mut scores = HashMap::<&str, TeamScores>::new();
2121+2222+ for line in results.lines() {
2323+ let mut split_iterator = line.split(',');
2424+ // NOTE: We use `unwrap` because we didn't deal with error handling yet.
2525+ let team_1_name = split_iterator.next().unwrap();
2626+ let team_2_name = split_iterator.next().unwrap();
2727+ let team_1_score: u8 = split_iterator.next().unwrap().parse().unwrap();
2828+ let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
2929+3030+ // TODO: Populate the scores table with the extracted details.
3131+ // Keep in mind that goals scored by team 1 will be the number of goals
3232+ // conceded by team 2. Similarly, goals scored by team 2 will be the
3333+ // number of goals conceded by team 1.
3434+ if scores.contains_key(&team_1_name) {
3535+ let t1: &mut TeamScores = scores.get_mut(&team_1_name).unwrap();
3636+ t1.goals_scored += team_1_score;
3737+ t1.goals_conceded += team_2_score;
3838+ } else {
3939+ let team_1_struct = TeamScores {
4040+ goals_scored: team_1_score.clone(),
4141+ goals_conceded: team_2_score.clone(),
4242+ };
4343+4444+ scores.insert(team_1_name, team_1_struct);
4545+ };
4646+4747+ if scores.contains_key(&team_2_name) {
4848+ let t2 = scores.get_mut(&team_2_name).unwrap();
4949+ t2.goals_scored += team_2_score;
5050+ t2.goals_conceded += team_1_score;
5151+ } else {
5252+ let team_2_struct = TeamScores {
5353+ goals_scored: team_2_score,
5454+ goals_conceded: team_1_score,
5555+ };
5656+ scores.insert(team_2_name, team_2_struct);
5757+ };
5858+ }
5959+6060+ scores
6161+}
6262+6363+fn main() {
6464+ // You can optionally experiment here.
6565+}
6666+6767+#[cfg(test)]
6868+mod tests {
6969+ use super::*;
7070+7171+ const RESULTS: &str = "England,France,4,2
7272+France,Italy,3,1
7373+Poland,Spain,2,0
7474+Germany,England,2,1
7575+England,Spain,1,0";
7676+7777+ #[test]
7878+ fn build_scores() {
7979+ let scores = build_scores_table(RESULTS);
8080+8181+ assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
8282+ .into_iter()
8383+ .all(|team_name| scores.contains_key(team_name)));
8484+ }
8585+8686+ #[test]
8787+ fn validate_team_score_1() {
8888+ let scores = build_scores_table(RESULTS);
8989+ let team = scores.get("England").unwrap();
9090+ assert_eq!(team.goals_scored, 6);
9191+ assert_eq!(team.goals_conceded, 4);
9292+ }
9393+9494+ #[test]
9595+ fn validate_team_score_2() {
9696+ let scores = build_scores_table(RESULTS);
9797+ let team = scores.get("Spain").unwrap();
9898+ assert_eq!(team.goals_scored, 0);
9999+ assert_eq!(team.goals_conceded, 3);
100100+ }
101101+}
+21
exercises/12_options/README.md
···11+# Options
22+33+Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
44+Option types are very common in Rust code, as they have a number of uses:
55+66+- Initial values
77+- Return values for functions that are not defined over their entire input range (partial functions)
88+- Return value for otherwise reporting simple errors, where None is returned on error
99+- Optional struct fields
1010+- Struct fields that can be loaned or "taken"
1111+- Optional function arguments
1212+- Nullable pointers
1313+- Swapping things out of difficult situations
1414+1515+## Further Information
1616+1717+- [Option Enum Format](https://doc.rust-lang.org/book/ch10-01-syntax.html#in-enum-definitions)
1818+- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
1919+- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
2020+- [if let](https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html)
2121+- [while let](https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html)
+45
exercises/12_options/options1.rs
···11+// This function returns how much icecream there is left in the fridge.
22+// If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00,
33+// someone eats it all, so no icecream is left (value 0). Return `None` if
44+// `hour_of_day` is higher than 23.
55+fn maybe_icecream(hour_of_day: u16) -> Option<u16> {
66+ // TODO: Complete the function body.
77+ let result: Option<u16>;
88+ if hour_of_day < 22 {
99+ result = Some(5);
1010+ } else if (22..=23).contains(&hour_of_day) {
1111+ result = Some(0)
1212+ } else {
1313+ result = None
1414+ }
1515+ result
1616+}
1717+1818+fn main() {
1919+ // You can optionally experiment here.
2020+}
2121+2222+#[cfg(test)]
2323+mod tests {
2424+ use super::*;
2525+2626+ #[test]
2727+ fn raw_value() {
2828+ // TODO: Fix this test. How do you get the value contained in the
2929+ // Option?
3030+ let icecreams = maybe_icecream(12).unwrap();
3131+3232+ assert_eq!(icecreams, 5); // Don't change this line.
3333+ }
3434+3535+ #[test]
3636+ fn check_icecream() {
3737+ assert_eq!(maybe_icecream(0), Some(5));
3838+ assert_eq!(maybe_icecream(9), Some(5));
3939+ assert_eq!(maybe_icecream(18), Some(5));
4040+ assert_eq!(maybe_icecream(22), Some(0));
4141+ assert_eq!(maybe_icecream(23), Some(0));
4242+ assert_eq!(maybe_icecream(24), None);
4343+ assert_eq!(maybe_icecream(25), None);
4444+ }
4545+}
+39
exercises/12_options/options2.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ #[test]
88+ fn simple_option() {
99+ let target = "rustlings";
1010+ let optional_target = Some(target);
1111+1212+ // TODO: Make this an if-let statement whose value is `Some`.
1313+ if let Some(word) = optional_target {
1414+ assert_eq!(word, target);
1515+ }
1616+ }
1717+1818+ #[test]
1919+ fn layered_option() {
2020+ let range = 10;
2121+ let mut optional_integers: Vec<Option<i8>> = vec![None];
2222+2323+ for i in 1..=range {
2424+ optional_integers.push(Some(i));
2525+ }
2626+2727+ let mut cursor = range;
2828+2929+ // TODO: Make this a while-let statement. Remember that `Vec::pop()`
3030+ // adds another layer of `Option`. You can do nested pattern matching
3131+ // in if-let and while-let statements.
3232+ while let Some(Some(integer)) = optional_integers.pop() {
3333+ assert_eq!(integer, cursor);
3434+ cursor -= 1;
3535+ }
3636+3737+ assert_eq!(cursor, 0);
3838+ }
3939+}
+17
exercises/12_options/options3.rs
···11+#[derive(Debug)]
22+struct Point {
33+ x: i32,
44+ y: i32,
55+}
66+77+fn main() {
88+ let optional_point = Some(Point { x: 100, y: 200 });
99+1010+ // TODO: Fix the compiler error by adding something to this match statement.
1111+ match optional_point {
1212+ Some(ref p) => println!("Co-ordinates are {},{}", p.x, p.y),
1313+ _ => panic!("No match!"),
1414+ }
1515+1616+ println!("{optional_point:?}"); // Don't change this line.
1717+}
+12
exercises/13_error_handling/README.md
···11+# Error handling
22+33+Most errors aren’t serious enough to require the program to stop entirely.
44+Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to.
55+For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process.
66+77+## Further information
88+99+- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
1010+- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
1111+- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html)
1212+- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html)
+41
exercises/13_error_handling/errors1.rs
···11+// TODO: This function refuses to generate text to be printed on a nametag if
22+// you pass it an empty string. It'd be nicer if it explained what the problem
33+// was instead of just returning `None`. Thankfully, Rust has a similar
44+// construct to `Option` that can be used to express error conditions. Change
55+// the function signature and body to return `Result<String, String>` instead
66+// of `Option<String>`.
77+fn generate_nametag_text(name: String) -> Result<String, String> {
88+ if name.is_empty() {
99+ // Empty names aren't allowed
1010+ Err("Empty names aren't allowed".to_string())
1111+ } else {
1212+ Ok(format!("Hi! My name is {name}"))
1313+ }
1414+}
1515+1616+fn main() {
1717+ // You can optionally experiment here.
1818+}
1919+2020+#[cfg(test)]
2121+mod tests {
2222+ use super::*;
2323+2424+ #[test]
2525+ fn generates_nametag_text_for_a_nonempty_name() {
2626+ assert_eq!(
2727+ generate_nametag_text("Beyoncé".to_string()).as_deref(),
2828+ Ok("Hi! My name is Beyoncé"),
2929+ );
3030+ }
3131+3232+ #[test]
3333+ fn explains_why_generating_nametag_text_fails() {
3434+ assert_eq!(
3535+ generate_nametag_text(String::new())
3636+ .as_ref()
3737+ .map_err(|e| e.as_str()),
3838+ Err("Empty names aren't allowed"),
3939+ );
4040+ }
4141+}
+50
exercises/13_error_handling/errors2.rs
···11+// Say we're writing a game where you can buy items with tokens. All items cost
22+// 5 tokens, and whenever you purchase items there is a processing fee of 1
33+// token. A player of the game will type in how many items they want to buy, and
44+// the `total_cost` function will calculate the total cost of the items. Since
55+// the player typed in the quantity, we get it as a string. They might have
66+// typed anything, not just numbers!
77+//
88+// Right now, this function isn't handling the error case at all. What we want
99+// to do is: If we call the `total_cost` function on a string that is not a
1010+// number, that function will return a `ParseIntError`. In that case, we want to
1111+// immediately return that error from our function and not try to multiply and
1212+// add.
1313+//
1414+// There are at least two ways to implement this that are both correct. But one
1515+// is a lot shorter!
1616+1717+use std::num::ParseIntError;
1818+1919+fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
2020+ let processing_fee = 1;
2121+ let cost_per_item = 5;
2222+2323+ // TODO: Handle the error case as described above.
2424+ let qty = item_quantity.parse::<i32>()?;
2525+2626+ Ok(qty * cost_per_item + processing_fee)
2727+}
2828+2929+fn main() {
3030+ // You can optionally experiment here.
3131+}
3232+3333+#[cfg(test)]
3434+mod tests {
3535+ use super::*;
3636+ use std::num::IntErrorKind;
3737+3838+ #[test]
3939+ fn item_quantity_is_a_valid_number() {
4040+ assert_eq!(total_cost("34"), Ok(171));
4141+ }
4242+4343+ #[test]
4444+ fn item_quantity_is_an_invalid_number() {
4545+ assert_eq!(
4646+ total_cost("beep boop").unwrap_err().kind(),
4747+ &IntErrorKind::InvalidDigit,
4848+ );
4949+ }
5050+}
+33
exercises/13_error_handling/errors3.rs
···11+// This is a program that is trying to use a completed version of the
22+// `total_cost` function from the previous exercise. It's not working though!
33+// Why not? What should we do to fix it?
44+55+use std::num::ParseIntError;
66+77+// Don't change this function.
88+fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
99+ let processing_fee = 1;
1010+ let cost_per_item = 5;
1111+ let qty = item_quantity.parse::<i32>()?;
1212+1313+ Ok(qty * cost_per_item + processing_fee)
1414+}
1515+1616+// TODO: Fix the compiler error by changing the signature and body of the
1717+// `main` function.
1818+fn main() -> Result<(), ParseIntError> {
1919+ let mut tokens = 100;
2020+ let pretend_user_input = "8";
2121+2222+ // Don't change this line.
2323+ let cost = total_cost(pretend_user_input)?;
2424+2525+ if cost > tokens {
2626+ println!("You can't afford that many!");
2727+ } else {
2828+ tokens -= cost;
2929+ println!("You now have {tokens} tokens.");
3030+ }
3131+3232+ Ok(())
3333+}
···11+// This exercise is an altered version of the `errors4` exercise. It uses some
22+// concepts that we won't get to until later in the course, like `Box` and the
33+// `From` trait. It's not important to understand them in detail right now, but
44+// you can read ahead if you like. For now, think of the `Box<dyn ???>` type as
55+// an "I want anything that does ???" type.
66+//
77+// In short, this particular use case for boxes is for when you want to own a
88+// value and you care only that it is a type which implements a particular
99+// trait. To do so, The `Box` is declared as of type `Box<dyn Trait>` where
1010+// `Trait` is the trait the compiler looks for on any value used in that
1111+// context. For this exercise, that context is the potential errors which
1212+// can be returned in a `Result`.
1313+1414+use std::error::Error;
1515+use std::fmt;
1616+1717+#[derive(PartialEq, Debug)]
1818+enum CreationError {
1919+ Negative,
2020+ Zero,
2121+}
2222+2323+// This is required so that `CreationError` can implement `Error`.
2424+impl fmt::Display for CreationError {
2525+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2626+ let description = match *self {
2727+ CreationError::Negative => "number is negative",
2828+ CreationError::Zero => "number is zero",
2929+ };
3030+ f.write_str(description)
3131+ }
3232+}
3333+3434+impl Error for CreationError {}
3535+3636+#[derive(PartialEq, Debug)]
3737+struct PositiveNonzeroInteger(u64);
3838+3939+impl PositiveNonzeroInteger {
4040+ fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
4141+ match value {
4242+ x if x < 0 => Err(CreationError::Negative),
4343+ 0 => Err(CreationError::Zero),
4444+ x => Ok(PositiveNonzeroInteger(x as u64)),
4545+ }
4646+ }
4747+}
4848+4949+// TODO: Add the correct return type `Result<(), Box<dyn ???>>`. What can we
5050+// use to describe both errors? Is there a trait which both errors implement?
5151+fn main() -> Result<(), Box<dyn Error>> {
5252+ let pretend_user_input = "42";
5353+ let x: i64 = pretend_user_input.parse()?;
5454+ println!("output={:?}", PositiveNonzeroInteger::new(x)?);
5555+ Ok(())
5656+}
+92
exercises/13_error_handling/errors6.rs
···11+// Using catch-all error types like `Box<dyn Error>` isn't recommended for
22+// library code where callers might want to make decisions based on the error
33+// content instead of printing it out or propagating it further. Here, we define
44+// a custom error type to make it possible for callers to decide what to do next
55+// when our function returns an error.
66+77+use std::num::ParseIntError;
88+99+#[derive(PartialEq, Debug)]
1010+enum CreationError {
1111+ Negative,
1212+ Zero,
1313+}
1414+1515+// A custom error type that we will be using in `PositiveNonzeroInteger::parse`.
1616+#[derive(PartialEq, Debug)]
1717+enum ParsePosNonzeroError {
1818+ Creation(CreationError),
1919+ ParseInt(ParseIntError),
2020+}
2121+2222+impl ParsePosNonzeroError {
2323+ fn from_creation(err: CreationError) -> Self {
2424+ Self::Creation(err)
2525+ }
2626+2727+ // TODO: Add another error conversion function here.
2828+ // fn from_parse_int(???) -> Self { ??? }
2929+ fn from_parse_int(err: ParseIntError) -> Self {
3030+ Self::ParseInt(err)
3131+ }
3232+}
3333+3434+#[derive(PartialEq, Debug)]
3535+struct PositiveNonzeroInteger(u64);
3636+3737+impl PositiveNonzeroInteger {
3838+ fn new(value: i64) -> Result<Self, CreationError> {
3939+ match value {
4040+ x if x < 0 => Err(CreationError::Negative),
4141+ 0 => Err(CreationError::Zero),
4242+ x => Ok(Self(x as u64)),
4343+ }
4444+ }
4545+4646+ fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
4747+ // TODO: change this to return an appropriate error instead of panicking
4848+ // when `parse()` returns an error.
4949+ let x: i64 = s.parse().map_err(ParsePosNonzeroError::from_parse_int)?;
5050+ Self::new(x).map_err(ParsePosNonzeroError::from_creation)
5151+ }
5252+}
5353+5454+fn main() {
5555+ // You can optionally experiment here.
5656+}
5757+5858+#[cfg(test)]
5959+mod test {
6060+ use super::*;
6161+6262+ #[test]
6363+ fn test_parse_error() {
6464+ assert!(matches!(
6565+ PositiveNonzeroInteger::parse("not a number"),
6666+ Err(ParsePosNonzeroError::ParseInt(_)),
6767+ ));
6868+ }
6969+7070+ #[test]
7171+ fn test_negative() {
7272+ assert_eq!(
7373+ PositiveNonzeroInteger::parse("-555"),
7474+ Err(ParsePosNonzeroError::Creation(CreationError::Negative)),
7575+ );
7676+ }
7777+7878+ #[test]
7979+ fn test_zero() {
8080+ assert_eq!(
8181+ PositiveNonzeroInteger::parse("0"),
8282+ Err(ParsePosNonzeroError::Creation(CreationError::Zero)),
8383+ );
8484+ }
8585+8686+ #[test]
8787+ fn test_positive() {
8888+ let x = PositiveNonzeroInteger::new(42).unwrap();
8989+ assert_eq!(x.0, 42);
9090+ assert_eq!(PositiveNonzeroInteger::parse("42"), Ok(x));
9191+ }
9292+}
+11
exercises/14_generics/README.md
···11+# Generics
22+33+Generics is the topic of generalizing types and functionalities to broader cases.
44+This is extremely useful for reducing code duplication in many ways, but can call for some rather involved syntax.
55+Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid.
66+The simplest and most common use of generics is for type parameters.
77+88+## Further information
99+1010+- [Generic Data Types](https://doc.rust-lang.org/book/ch10-01-syntax.html)
1111+- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html)
+18
exercises/14_generics/generics1.rs
···11+// `Vec<T>` is generic over the type `T`. In most cases, the compiler is able to
22+// infer `T`, for example after pushing a value with a concrete type to the vector.
33+// But in this exercise, the compiler needs some help through a type annotation.
44+55+fn main() {
66+ // TODO: Fix the compiler error by annotating the type of the vector
77+ // `Vec<T>`. Choose `T` as some integer type that can be created from
88+ // `u8` and `i8`.
99+ let mut numbers: Vec<i32> = Vec::new();
1010+1111+ // Don't change the lines below.
1212+ let n1: u8 = 42;
1313+ numbers.push(n1.into());
1414+ let n2: i8 = -1;
1515+ numbers.push(n2.into());
1616+1717+ println!("{numbers:?}");
1818+}
+31
exercises/14_generics/generics2.rs
···11+// This powerful wrapper provides the ability to store a positive integer value.
22+// TODO: Rewrite it using a generic so that it supports wrapping ANY type.
33+struct Wrapper<T> {
44+ value: T,
55+}
66+77+// TODO: Adapt the struct's implementation to be generic over the wrapped value.
88+impl<T> Wrapper<T> {
99+ fn new(value: T) -> Self {
1010+ Wrapper { value }
1111+ }
1212+}
1313+1414+fn main() {
1515+ // You can optionally experiment here.
1616+}
1717+1818+#[cfg(test)]
1919+mod tests {
2020+ use super::*;
2121+2222+ #[test]
2323+ fn store_u32_in_wrapper() {
2424+ assert_eq!(Wrapper::new(42).value, 42);
2525+ }
2626+2727+ #[test]
2828+ fn store_str_in_wrapper() {
2929+ assert_eq!(Wrapper::new("Foo").value, "Foo");
3030+ }
3131+}
+19
exercises/15_traits/README.md
···11+# Traits
22+33+A trait is a collection of methods.
44+55+Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`.
66+77+In this way, traits are somewhat similar to Java interfaces and C++ abstract classes.
88+99+Some additional common Rust traits include:
1010+1111+- `Clone` (the `clone` method)
1212+- `Display` (which allows formatted display via `{}`)
1313+- `Debug` (which allows formatted display via `{:?}`)
1414+1515+Because traits indicate shared behavior between data types, they are useful when writing generics.
1616+1717+## Further information
1818+1919+- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)
+33
exercises/15_traits/traits1.rs
···11+// The trait `AppendBar` has only one function which appends "Bar" to any object
22+// implementing this trait.
33+trait AppendBar {
44+ fn append_bar(self) -> Self;
55+}
66+77+impl AppendBar for String {
88+ // TODO: Implement `AppendBar` for the type `String`.
99+ fn append_bar(self) -> String {
1010+ format!("{self}Bar")
1111+ }
1212+}
1313+1414+fn main() {
1515+ let s = String::from("Foo");
1616+ let s = s.append_bar();
1717+ println!("s: {s}");
1818+}
1919+2020+#[cfg(test)]
2121+mod tests {
2222+ use super::*;
2323+2424+ #[test]
2525+ fn is_foo_bar() {
2626+ assert_eq!(String::from("Foo").append_bar(), "FooBar");
2727+ }
2828+2929+ #[test]
3030+ fn is_bar_bar() {
3131+ assert_eq!(String::from("").append_bar().append_bar(), "BarBar");
3232+ }
3333+}
+29
exercises/15_traits/traits2.rs
···11+trait AppendBar {
22+ fn append_bar(self) -> Self;
33+}
44+55+// TODO: Implement the trait `AppendBar` for a vector of strings.
66+// `append_bar` should push the string "Bar" into the vector.
77+88+impl AppendBar for Vec<String> {
99+ fn append_bar(mut self) -> Self {
1010+ self.push(String::from("Bar"));
1111+ self
1212+ }
1313+}
1414+1515+fn main() {
1616+ // You can optionally experiment here.
1717+}
1818+1919+#[cfg(test)]
2020+mod tests {
2121+ use super::*;
2222+2323+ #[test]
2424+ fn is_vec_pop_eq_bar() {
2525+ let mut foo = vec![String::from("Foo")].append_bar();
2626+ assert_eq!(foo.pop().unwrap(), "Bar");
2727+ assert_eq!(foo.pop().unwrap(), "Foo");
2828+ }
2929+}
+40
exercises/15_traits/traits3.rs
···11+trait Licensed {
22+ // TODO: Add a default implementation for `licensing_info` so that
33+ // implementors like the two structs below can share that default behavior
44+ // without repeating the function.
55+ // The default license information should be the string "Default license".
66+ fn licensing_info(&self) -> String {
77+ "Default license".to_string()
88+ }
99+}
1010+1111+struct SomeSoftware {
1212+ version_number: i32,
1313+}
1414+1515+struct OtherSoftware {
1616+ version_number: String,
1717+}
1818+1919+impl Licensed for SomeSoftware {} // Don't edit this line.
2020+impl Licensed for OtherSoftware {} // Don't edit this line.
2121+2222+fn main() {
2323+ // You can optionally experiment here.
2424+}
2525+2626+#[cfg(test)]
2727+mod tests {
2828+ use super::*;
2929+3030+ #[test]
3131+ fn is_licensing_info_the_same() {
3232+ let licensing_info = "Default license";
3333+ let some_software = SomeSoftware { version_number: 1 };
3434+ let other_software = OtherSoftware {
3535+ version_number: "v2.0.0".to_string(),
3636+ };
3737+ assert_eq!(some_software.licensing_info(), licensing_info);
3838+ assert_eq!(other_software.licensing_info(), licensing_info);
3939+ }
4040+}
+35
exercises/15_traits/traits4.rs
···11+trait Licensed {
22+ fn licensing_info(&self) -> String {
33+ "Default license".to_string()
44+ }
55+}
66+77+struct SomeSoftware;
88+struct OtherSoftware;
99+1010+impl Licensed for SomeSoftware {}
1111+impl Licensed for OtherSoftware {}
1212+1313+// TODO: Fix the compiler error by only changing the signature of this function.
1414+fn compare_license_types(software1: impl Licensed, software2: impl Licensed) -> bool {
1515+ software1.licensing_info() == software2.licensing_info()
1616+}
1717+1818+fn main() {
1919+ // You can optionally experiment here.
2020+}
2121+2222+#[cfg(test)]
2323+mod tests {
2424+ use super::*;
2525+2626+ #[test]
2727+ fn compare_license_information() {
2828+ assert!(compare_license_types(SomeSoftware, OtherSoftware));
2929+ }
3030+3131+ #[test]
3232+ fn compare_license_information_backwards() {
3333+ assert!(compare_license_types(OtherSoftware, SomeSoftware));
3434+ }
3535+}
+42
exercises/15_traits/traits5.rs
···11+trait SomeTrait {
22+ fn some_function(&self) -> bool {
33+ true
44+ }
55+}
66+77+trait OtherTrait {
88+ fn other_function(&self) -> bool {
99+ true
1010+ }
1111+}
1212+1313+struct SomeStruct;
1414+impl SomeTrait for SomeStruct {}
1515+impl OtherTrait for SomeStruct {}
1616+1717+struct OtherStruct;
1818+impl SomeTrait for OtherStruct {}
1919+impl OtherTrait for OtherStruct {}
2020+2121+// TODO: Fix the compiler error by only changing the signature of this function.
2222+fn some_func<T>(item: T) -> bool
2323+where
2424+ T: SomeTrait + OtherTrait,
2525+{
2626+ item.some_function() && item.other_function()
2727+}
2828+2929+fn main() {
3030+ // You can optionally experiment here.
3131+}
3232+3333+#[cfg(test)]
3434+mod tests {
3535+ use super::*;
3636+3737+ #[test]
3838+ fn test_some_func() {
3939+ assert!(some_func(SomeStruct));
4040+ assert!(some_func(OtherStruct));
4141+ }
4242+}
+22
exercises/16_lifetimes/README.md
···11+# Lifetimes
22+33+Lifetimes tell the compiler how to check whether references live long
44+enough to be valid in any given situation. For example lifetimes say
55+"make sure parameter 'a' lives as long as parameter 'b' so that the return
66+value is valid".
77+88+They are only necessary on borrows, i.e. references,
99+since copied parameters or moves are owned in their scope and cannot
1010+be referenced outside. Lifetimes mean that calling code of e.g. functions
1111+can be checked to make sure their arguments are valid. Lifetimes are
1212+restrictive of their callers.
1313+1414+If you'd like to learn more about lifetime annotations, the
1515+[lifetimekata](https://tfpk.github.io/lifetimekata/) project
1616+has a similar style of exercises to Rustlings, but is all about
1717+learning to write lifetime annotations.
1818+1919+## Further information
2020+2121+- [Lifetimes (in Rust By Example)](https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime.html)
2222+- [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
+28
exercises/16_lifetimes/lifetimes1.rs
···11+// The Rust compiler needs to know how to check whether supplied references are
22+// valid, so that it can let the programmer know if a reference is at risk of
33+// going out of scope before it is used. Remember, references are borrows and do
44+// not own their own data. What if their owner goes out of scope?
55+66+// TODO: Fix the compiler error by updating the function signature.
77+fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
88+ if x.len() > y.len() {
99+ x
1010+ } else {
1111+ y
1212+ }
1313+}
1414+1515+fn main() {
1616+ // You can optionally experiment here.
1717+}
1818+1919+#[cfg(test)]
2020+mod tests {
2121+ use super::*;
2222+2323+ #[test]
2424+ fn test_longest() {
2525+ assert_eq!(longest("abcd", "123"), "abcd");
2626+ assert_eq!(longest("abc", "1234"), "1234");
2727+ }
2828+}
+20
exercises/16_lifetimes/lifetimes2.rs
···11+// Don't change this function.
22+fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
33+ if x.len() > y.len() {
44+ x
55+ } else {
66+ y
77+ }
88+}
99+1010+fn main() {
1111+ // TODO: Fix the compiler error by moving one line.
1212+1313+ let string1 = String::from("long string is long");
1414+ let string2 = String::from("xyz");
1515+ let result;
1616+ {
1717+ result = longest(&string1, &string2);
1818+ }
1919+ println!("The longest string is '{result}'");
2020+}
+16
exercises/16_lifetimes/lifetimes3.rs
···11+// Lifetimes are also needed when structs hold references.
22+33+// TODO: Fix the compiler errors about the struct.
44+struct Book<'a> {
55+ author: &'a str,
66+ title: &'a str,
77+}
88+99+fn main() {
1010+ let book = Book {
1111+ author: "George Orwell",
1212+ title: "1984",
1313+ };
1414+1515+ println!("{} by {}", book.title, book.author);
1616+}
+7
exercises/17_tests/README.md
···11+# Tests
22+33+Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass!
44+55+## Further information
66+77+- [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html)
+25
exercises/17_tests/tests1.rs
···11+// Tests are important to ensure that your code does what you think it should
22+// do.
33+44+fn is_even(n: i64) -> bool {
55+ n % 2 == 0
66+}
77+88+fn main() {
99+ // You can optionally experiment here.
1010+}
1111+1212+#[cfg(test)]
1313+mod tests {
1414+ // TODO: Import `is_even`. You can use a wildcard to import everything in
1515+ // the outer module.
1616+1717+ use super::is_even;
1818+1919+ #[test]
2020+ fn you_can_assert() {
2121+ // TODO: Test the function `is_even` with some values.
2222+ assert!(is_even(2));
2323+ assert!(is_even(4));
2424+ }
2525+}
+23
exercises/17_tests/tests2.rs
···11+// Calculates the power of 2 using a bit shift.
22+// `1 << n` is equivalent to "2 to the power of n".
33+fn power_of_2(n: u8) -> u64 {
44+ 1 << n
55+}
66+77+fn main() {
88+ // You can optionally experiment here.
99+}
1010+1111+#[cfg(test)]
1212+mod tests {
1313+ use super::*;
1414+1515+ #[test]
1616+ fn you_can_assert_eq() {
1717+ // TODO: Test the function `power_of_2` with some values.
1818+ assert_eq!(power_of_2(1), 2);
1919+ assert_eq!(power_of_2(2), 4);
2020+ assert_eq!(power_of_2(3), 8);
2121+ assert_eq!(power_of_2(4), 16);
2222+ }
2323+}
+51
exercises/17_tests/tests3.rs
···11+struct Rectangle {
22+ width: i32,
33+ height: i32,
44+}
55+66+impl Rectangle {
77+ // Don't change this function.
88+ fn new(width: i32, height: i32) -> Self {
99+ if width <= 0 || height <= 0 {
1010+ // Returning a `Result` would be better here. But we want to learn
1111+ // how to test functions that can panic.
1212+ panic!("Rectangle width and height must be positive");
1313+ }
1414+1515+ Rectangle { width, height }
1616+ }
1717+}
1818+1919+fn main() {
2020+ // You can optionally experiment here.
2121+}
2222+2323+#[cfg(test)]
2424+mod tests {
2525+ use super::*;
2626+2727+ #[test]
2828+ fn correct_width_and_height() {
2929+ // TODO: This test should check if the rectangle has the size that we
3030+ // pass to its constructor.
3131+ let rect = Rectangle::new(10, 20);
3232+ assert_eq!(rect.width, 10); // Check width
3333+ assert_eq!(rect.height, 20); // Check height
3434+ }
3535+3636+ // TODO: This test should check if the program panics when we try to create
3737+ // a rectangle with negative width.
3838+ #[test]
3939+ #[should_panic(expected = "Rectangle width and height must be positive")]
4040+ fn negative_width() {
4141+ let _rect = Rectangle::new(-10, 10);
4242+ }
4343+4444+ // TODO: This test should check if the program panics when we try to create
4545+ // a rectangle with negative height.
4646+ #[test]
4747+ #[should_panic(expected = "Rectangle width and height must be positive")]
4848+ fn negative_height() {
4949+ let _rect = Rectangle::new(10, -10);
5050+ }
5151+}
+8
exercises/18_iterators/README.md
···11+# Iterators
22+33+This section will teach you about Iterators.
44+55+## Further information
66+77+- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html)
88+- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/)
+25
exercises/18_iterators/iterators1.rs
···11+// When performing operations on elements within a collection, iterators are
22+// essential. This module helps you get familiar with the structure of using an
33+// iterator and how to go through elements within an iterable collection.
44+55+fn main() {
66+ // You can optionally experiment here.
77+}
88+99+#[cfg(test)]
1010+mod tests {
1111+ #[test]
1212+ fn iterators() {
1313+ let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"];
1414+1515+ // TODO: Create an iterator over the array.
1616+ let mut fav_fruits_iterator = my_fav_fruits.iter();
1717+1818+ assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
1919+ assert_eq!(fav_fruits_iterator.next(), Some(&"custard apple")); // TODO: Replace `todo!()`
2020+ assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
2121+ assert_eq!(fav_fruits_iterator.next(), Some(&"peach")); // TODO: Replace `todo!()`
2222+ assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
2323+ assert_eq!(fav_fruits_iterator.next(), None); // TODO: Replace `todo!()`
2424+ }
2525+}
+59
exercises/18_iterators/iterators2.rs
···11+// In this exercise, you'll learn some of the unique advantages that iterators
22+// can offer.
33+44+// TODO: Complete the `capitalize_first` function.
55+// "hello" -> "Hello"
66+fn capitalize_first(input: &str) -> String {
77+ let mut chars = input.chars();
88+ match chars.next() {
99+ None => String::new(),
1010+ Some(first) => first.to_uppercase().to_string() + chars.as_str(),
1111+ }
1212+}
1313+1414+// TODO: Apply the `capitalize_first` function to a slice of string slices.
1515+// Return a vector of strings.
1616+// ["hello", "world"] -> ["Hello", "World"]
1717+fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
1818+ // ???
1919+ words.iter().map(|word| capitalize_first(word)).collect()
2020+}
2121+2222+// TODO: Apply the `capitalize_first` function again to a slice of string
2323+// slices. Return a single string.
2424+// ["hello", " ", "world"] -> "Hello World"
2525+fn capitalize_words_string(words: &[&str]) -> String {
2626+ // ???
2727+ words.iter().map(|word| capitalize_first(word)).collect()
2828+}
2929+3030+fn main() {
3131+ // You can optionally experiment here.
3232+}
3333+3434+#[cfg(test)]
3535+mod tests {
3636+ use super::*;
3737+3838+ #[test]
3939+ fn test_success() {
4040+ assert_eq!(capitalize_first("hello"), "Hello");
4141+ }
4242+4343+ #[test]
4444+ fn test_empty() {
4545+ assert_eq!(capitalize_first(""), "");
4646+ }
4747+4848+ #[test]
4949+ fn test_iterate_string_vec() {
5050+ let words = vec!["hello", "world"];
5151+ assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
5252+ }
5353+5454+ #[test]
5555+ fn test_iterate_into_string() {
5656+ let words = vec!["hello", " ", "world"];
5757+ assert_eq!(capitalize_words_string(&words), "Hello World");
5858+ }
5959+}
+84
exercises/18_iterators/iterators3.rs
···11+#[derive(Debug, PartialEq, Eq)]
22+enum DivisionError {
33+ // Example: 42 / 0
44+ DivideByZero,
55+ // Only case for `i64`: `i64::MIN / -1` because the result is `i64::MAX + 1`
66+ IntegerOverflow,
77+ // Example: 5 / 2 = 2.5
88+ NotDivisible,
99+}
1010+1111+// TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
1212+// Otherwise, return a suitable error.
1313+fn divide(a: i64, b: i64) -> Result<i64, DivisionError> {
1414+ if b == 0 {
1515+ return Err(DivisionError::DivideByZero);
1616+ }
1717+ if a == i64::MIN && b == -1 {
1818+ return Err(DivisionError::IntegerOverflow);
1919+ }
2020+ if a % b != 0 {
2121+ return Err(DivisionError::NotDivisible);
2222+ }
2323+ Ok(a / b)
2424+}
2525+2626+// TODO: Add the correct return type and complete the function body.
2727+// Desired output: `Ok([1, 11, 1426, 3])`
2828+fn result_with_list() -> Result<Vec<i64>, DivisionError> {
2929+ let numbers = [27, 297, 38502, 81];
3030+ let division_results = numbers.into_iter().map(|n| divide(n, 27));
3131+ division_results.collect()
3232+}
3333+3434+// TODO: Add the correct return type and complete the function body.
3535+// Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]`
3636+fn list_of_results() -> Vec<Result<i64, DivisionError>> {
3737+ let numbers = [27, 297, 38502, 81];
3838+ let division_results = numbers.into_iter().map(|n| divide(n, 27));
3939+ division_results.collect()
4040+}
4141+4242+fn main() {
4343+ // You can optionally experiment here.
4444+}
4545+4646+#[cfg(test)]
4747+mod tests {
4848+ use super::*;
4949+5050+ #[test]
5151+ fn test_success() {
5252+ assert_eq!(divide(81, 9), Ok(9));
5353+ }
5454+5555+ #[test]
5656+ fn test_divide_by_0() {
5757+ assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
5858+ }
5959+6060+ #[test]
6161+ fn test_integer_overflow() {
6262+ assert_eq!(divide(i64::MIN, -1), Err(DivisionError::IntegerOverflow));
6363+ }
6464+6565+ #[test]
6666+ fn test_not_divisible() {
6767+ assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));
6868+ }
6969+7070+ #[test]
7171+ fn test_divide_0_by_something() {
7272+ assert_eq!(divide(0, 81), Ok(0));
7373+ }
7474+7575+ #[test]
7676+ fn test_result_with_list() {
7777+ assert_eq!(result_with_list().unwrap(), [1, 11, 1426, 3]);
7878+ }
7979+8080+ #[test]
8181+ fn test_list_of_results() {
8282+ assert_eq!(list_of_results(), [Ok(1), Ok(11), Ok(1426), Ok(3)]);
8383+ }
8484+}
+48
exercises/18_iterators/iterators4.rs
···11+fn factorial(num: u64) -> u64 {
22+ // TODO: Complete this function to return the factorial of `num` which is
33+ // defined as `1 * 2 * 3 * … * num`.
44+ // https://en.wikipedia.org/wiki/Factorial
55+ //
66+ // Do not use:
77+ // - early returns (using the `return` keyword explicitly)
88+ // Try not to use:
99+ // - imperative style loops (for/while)
1010+ // - additional variables
1111+ // For an extra challenge, don't use:
1212+ // - recursion
1313+ let mut result = 1;
1414+1515+ for x in 2..=num {
1616+ result *= x;
1717+ }
1818+1919+ result
2020+}
2121+2222+fn main() {
2323+ // You can optionally experiment here.
2424+}
2525+2626+#[cfg(test)]
2727+mod tests {
2828+ use super::*;
2929+3030+ #[test]
3131+ fn factorial_of_0() {
3232+ assert_eq!(factorial(0), 1);
3333+ }
3434+3535+ #[test]
3636+ fn factorial_of_1() {
3737+ assert_eq!(factorial(1), 1);
3838+ }
3939+ #[test]
4040+ fn factorial_of_2() {
4141+ assert_eq!(factorial(2), 2);
4242+ }
4343+4444+ #[test]
4545+ fn factorial_of_4() {
4646+ assert_eq!(factorial(4), 24);
4747+ }
4848+}
+158
exercises/18_iterators/iterators5.rs
···11+// Let's define a simple model to track Rustlings' exercise progress. Progress
22+// will be modelled using a hash map. The name of the exercise is the key and
33+// the progress is the value. Two counting functions were created to count the
44+// number of exercises with a given progress. Recreate this counting
55+// functionality using iterators. Try to not use imperative loops (for/while).
66+77+use std::collections::HashMap;
88+99+#[derive(Clone, Copy, PartialEq, Eq)]
1010+enum Progress {
1111+ None,
1212+ Some,
1313+ Complete,
1414+}
1515+1616+fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
1717+ let mut count = 0;
1818+ for val in map.values() {
1919+ if *val == value {
2020+ count += 1;
2121+ }
2222+ }
2323+ count
2424+}
2525+2626+// TODO: Implement the functionality of `count_for` but with an iterator instead
2727+// of a `for` loop.
2828+fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
2929+ // `map` is a hash map with `String` keys and `Progress` values.
3030+ // map = { "variables1": Complete, "from_str": None, … }
3131+ map.values().filter(|val| **val == value).count()
3232+}
3333+3434+fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
3535+ let mut count = 0;
3636+ for map in collection {
3737+ for val in map.values() {
3838+ if *val == value {
3939+ count += 1;
4040+ }
4141+ }
4242+ }
4343+ count
4444+}
4545+4646+// TODO: Implement the functionality of `count_collection_for` but with an
4747+// iterator instead of a `for` loop.
4848+fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
4949+ // `collection` is a slice of hash maps.
5050+ // collection = [{ "variables1": Complete, "from_str": None, … },
5151+ // { "variables2": Complete, … }, … ]
5252+ collection
5353+ .iter()
5454+ .map(|map| count_iterator(map, value))
5555+ .sum()
5656+}
5757+5858+fn main() {
5959+ // You can optionally experiment here.
6060+}
6161+6262+#[cfg(test)]
6363+mod tests {
6464+ use super::*;
6565+6666+ fn get_map() -> HashMap<String, Progress> {
6767+ use Progress::*;
6868+6969+ let mut map = HashMap::new();
7070+ map.insert(String::from("variables1"), Complete);
7171+ map.insert(String::from("functions1"), Complete);
7272+ map.insert(String::from("hashmap1"), Complete);
7373+ map.insert(String::from("arc1"), Some);
7474+ map.insert(String::from("as_ref_mut"), None);
7575+ map.insert(String::from("from_str"), None);
7676+7777+ map
7878+ }
7979+8080+ fn get_vec_map() -> Vec<HashMap<String, Progress>> {
8181+ use Progress::*;
8282+8383+ let map = get_map();
8484+8585+ let mut other = HashMap::new();
8686+ other.insert(String::from("variables2"), Complete);
8787+ other.insert(String::from("functions2"), Complete);
8888+ other.insert(String::from("if1"), Complete);
8989+ other.insert(String::from("from_into"), None);
9090+ other.insert(String::from("try_from_into"), None);
9191+9292+ vec![map, other]
9393+ }
9494+9595+ #[test]
9696+ fn count_complete() {
9797+ let map = get_map();
9898+ assert_eq!(count_iterator(&map, Progress::Complete), 3);
9999+ }
100100+101101+ #[test]
102102+ fn count_some() {
103103+ let map = get_map();
104104+ assert_eq!(count_iterator(&map, Progress::Some), 1);
105105+ }
106106+107107+ #[test]
108108+ fn count_none() {
109109+ let map = get_map();
110110+ assert_eq!(count_iterator(&map, Progress::None), 2);
111111+ }
112112+113113+ #[test]
114114+ fn count_complete_equals_for() {
115115+ let map = get_map();
116116+ let progress_states = [Progress::Complete, Progress::Some, Progress::None];
117117+ for progress_state in progress_states {
118118+ assert_eq!(
119119+ count_for(&map, progress_state),
120120+ count_iterator(&map, progress_state),
121121+ );
122122+ }
123123+ }
124124+125125+ #[test]
126126+ fn count_collection_complete() {
127127+ let collection = get_vec_map();
128128+ assert_eq!(
129129+ count_collection_iterator(&collection, Progress::Complete),
130130+ 6,
131131+ );
132132+ }
133133+134134+ #[test]
135135+ fn count_collection_some() {
136136+ let collection = get_vec_map();
137137+ assert_eq!(count_collection_iterator(&collection, Progress::Some), 1);
138138+ }
139139+140140+ #[test]
141141+ fn count_collection_none() {
142142+ let collection = get_vec_map();
143143+ assert_eq!(count_collection_iterator(&collection, Progress::None), 4);
144144+ }
145145+146146+ #[test]
147147+ fn count_collection_equals_for() {
148148+ let collection = get_vec_map();
149149+ let progress_states = [Progress::Complete, Progress::Some, Progress::None];
150150+151151+ for progress_state in progress_states {
152152+ assert_eq!(
153153+ count_collection_for(&collection, progress_state),
154154+ count_collection_iterator(&collection, progress_state),
155155+ );
156156+ }
157157+ }
158158+}
+12
exercises/19_smart_pointers/README.md
···11+# Smart Pointers
22+33+In Rust, smart pointers are variables that contain an address in memory and reference some other data, but they also have additional metadata and capabilities.
44+Smart pointers in Rust often own the data they point to, while references only borrow data.
55+66+## Further Information
77+88+- [Smart Pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
99+- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html)
1010+- [Rc\<T\>, the Reference Counted Smart Pointer](https://doc.rust-lang.org/book/ch15-04-rc.html)
1111+- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
1212+- [Cow Documentation](https://doc.rust-lang.org/std/borrow/enum.Cow.html)
+47
exercises/19_smart_pointers/arc1.rs
···11+// In this exercise, we are given a `Vec` of `u32` called `numbers` with values
22+// ranging from 0 to 99. We would like to use this set of numbers within 8
33+// different threads simultaneously. Each thread is going to get the sum of
44+// every eighth value with an offset.
55+//
66+// The first thread (offset 0), will sum 0, 8, 16, …
77+// The second thread (offset 1), will sum 1, 9, 17, …
88+// The third thread (offset 2), will sum 2, 10, 18, …
99+// …
1010+// The eighth thread (offset 7), will sum 7, 15, 23, …
1111+//
1212+// Each thread should own a reference-counting pointer to the vector of
1313+// numbers. But `Rc` isn't thread-safe. Therefore, we need to use `Arc`.
1414+//
1515+// Don't get distracted by how threads are spawned and joined. We will practice
1616+// that later in the exercises about threads.
1717+1818+// Don't change the lines below.
1919+#![forbid(unused_imports)]
2020+use std::{sync::Arc, thread};
2121+2222+fn main() {
2323+ let numbers: Vec<_> = (0..100u32).collect();
2424+2525+ // TODO: Define `shared_numbers` by using `Arc`.
2626+ // let shared_numbers = ???;
2727+ let shared_numbers = Arc::new(numbers);
2828+2929+ let mut join_handles = Vec::new();
3030+3131+ for offset in 0..8 {
3232+ // TODO: Define `child_numbers` using `shared_numbers`.
3333+ // let child_numbers = ???;
3434+ let child_numbers = Arc::clone(&shared_numbers);
3535+3636+ let handle = thread::spawn(move || {
3737+ let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
3838+ println!("Sum of offset {offset} is {sum}");
3939+ });
4040+4141+ join_handles.push(handle);
4242+ }
4343+4444+ for handle in join_handles.into_iter() {
4545+ handle.join().unwrap();
4646+ }
4747+}
+50
exercises/19_smart_pointers/box1.rs
···11+// At compile time, Rust needs to know how much space a type takes up. This
22+// becomes problematic for recursive types, where a value can have as part of
33+// itself another value of the same type. To get around the issue, we can use a
44+// `Box` - a smart pointer used to store data on the heap, which also allows us
55+// to wrap a recursive type.
66+//
77+// The recursive type we're implementing in this exercise is the "cons list", a
88+// data structure frequently found in functional programming languages. Each
99+// item in a cons list contains two elements: The value of the current item and
1010+// the next item. The last item is a value called `Nil`.
1111+1212+// TODO: Use a `Box` in the enum definition to make the code compile.
1313+#[derive(PartialEq, Debug)]
1414+enum List {
1515+ Cons(i32, Box<List>),
1616+ Nil,
1717+}
1818+1919+// TODO: Create an empty cons list.
2020+fn create_empty_list() -> List {
2121+ List::Nil
2222+}
2323+2424+// TODO: Create a non-empty cons list.
2525+fn create_non_empty_list() -> List {
2626+ List::Cons(42, Box::new(List::Nil))
2727+}
2828+2929+fn main() {
3030+ println!("This is an empty cons list: {:?}", create_empty_list());
3131+ println!(
3232+ "This is a non-empty cons list: {:?}",
3333+ create_non_empty_list(),
3434+ );
3535+}
3636+3737+#[cfg(test)]
3838+mod tests {
3939+ use super::*;
4040+4141+ #[test]
4242+ fn test_create_empty_list() {
4343+ assert_eq!(create_empty_list(), List::Nil);
4444+ }
4545+4646+ #[test]
4747+ fn test_create_non_empty_list() {
4848+ assert_ne!(create_empty_list(), create_non_empty_list());
4949+ }
5050+}
+69
exercises/19_smart_pointers/cow1.rs
···11+// This exercise explores the `Cow` (Clone-On-Write) smart pointer. It can
22+// enclose and provide immutable access to borrowed data and clone the data
33+// lazily when mutation or ownership is required. The type is designed to work
44+// with general borrowed data via the `Borrow` trait.
55+66+use std::borrow::Cow;
77+88+fn abs_all(input: &mut Cow<[i32]>) {
99+ for ind in 0..input.len() {
1010+ let value = input[ind];
1111+ if value < 0 {
1212+ // Clones into a vector if not already owned.
1313+ input.to_mut()[ind] = -value;
1414+ }
1515+ }
1616+}
1717+1818+fn main() {
1919+ // You can optionally experiment here.
2020+}
2121+2222+#[cfg(test)]
2323+mod tests {
2424+ use super::*;
2525+2626+ #[test]
2727+ fn reference_mutation() {
2828+ // Clone occurs because `input` needs to be mutated.
2929+ let vec = vec![-1, 0, 1];
3030+ let mut input = Cow::from(&vec);
3131+ abs_all(&mut input);
3232+ assert!(matches!(input, Cow::Owned(_)));
3333+ }
3434+3535+ #[test]
3636+ fn reference_no_mutation() {
3737+ // No clone occurs because `input` doesn't need to be mutated.
3838+ let vec = vec![0, 1, 2];
3939+ let mut input = Cow::from(&vec);
4040+ abs_all(&mut input);
4141+ // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
4242+ assert!(matches!(input, Cow::Borrowed(_)));
4343+ }
4444+4545+ #[test]
4646+ fn owned_no_mutation() {
4747+ // We can also pass `vec` without `&` so `Cow` owns it directly. In this
4848+ // case, no mutation occurs (all numbers are already absolute) and thus
4949+ // also no clone. But the result is still owned because it was never
5050+ // borrowed or mutated.
5151+ let vec = vec![0, 1, 2];
5252+ let mut input = Cow::from(vec);
5353+ abs_all(&mut input);
5454+ // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
5555+ assert!(matches!(input, Cow::Owned(_)));
5656+ }
5757+5858+ #[test]
5959+ fn owned_mutation() {
6060+ // Of course this is also the case if a mutation does occur (not all
6161+ // numbers are absolute). In this case, the call to `to_mut()` in the
6262+ // `abs_all` function returns a reference to the same data as before.
6363+ let vec = vec![-1, 0, 1];
6464+ let mut input = Cow::from(vec);
6565+ abs_all(&mut input);
6666+ // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
6767+ assert!(matches!(input, Cow::Owned(_)));
6868+ }
6969+}
+108
exercises/19_smart_pointers/rc1.rs
···11+// In this exercise, we want to express the concept of multiple owners via the
22+// `Rc<T>` type. This is a model of our solar system - there is a `Sun` type and
33+// multiple `Planet`s. The planets take ownership of the sun, indicating that
44+// they revolve around the sun.
55+66+use std::rc::Rc;
77+88+#[derive(Debug)]
99+struct Sun;
1010+1111+#[derive(Debug)]
1212+enum Planet {
1313+ Mercury(Rc<Sun>),
1414+ Venus(Rc<Sun>),
1515+ Earth(Rc<Sun>),
1616+ Mars(Rc<Sun>),
1717+ Jupiter(Rc<Sun>),
1818+ Saturn(Rc<Sun>),
1919+ Uranus(Rc<Sun>),
2020+ Neptune(Rc<Sun>),
2121+}
2222+2323+impl Planet {
2424+ fn details(&self) {
2525+ println!("Hi from {self:?}!");
2626+ }
2727+}
2828+2929+fn main() {
3030+ // You can optionally experiment here.
3131+}
3232+3333+#[cfg(test)]
3434+mod tests {
3535+ use super::*;
3636+3737+ #[test]
3838+ fn rc1() {
3939+ let sun = Rc::new(Sun);
4040+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
4141+4242+ let mercury = Planet::Mercury(Rc::clone(&sun));
4343+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
4444+ mercury.details();
4545+4646+ let venus = Planet::Venus(Rc::clone(&sun));
4747+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
4848+ venus.details();
4949+5050+ let earth = Planet::Earth(Rc::clone(&sun));
5151+ println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
5252+ earth.details();
5353+5454+ let mars = Planet::Mars(Rc::clone(&sun));
5555+ println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
5656+ mars.details();
5757+5858+ let jupiter = Planet::Jupiter(Rc::clone(&sun));
5959+ println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
6060+ jupiter.details();
6161+6262+ // TODO
6363+ let saturn = Planet::Saturn(Rc::clone(&sun));
6464+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
6565+ saturn.details();
6666+6767+ // TODO
6868+ let uranus = Planet::Uranus(Rc::clone(&sun));
6969+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
7070+ uranus.details();
7171+7272+ // TODO
7373+ let neptune = Planet::Neptune(Rc::clone(&sun));
7474+ println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
7575+ neptune.details();
7676+7777+ assert_eq!(Rc::strong_count(&sun), 9);
7878+7979+ drop(neptune);
8080+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
8181+8282+ drop(uranus);
8383+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
8484+8585+ drop(saturn);
8686+ println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
8787+8888+ drop(jupiter);
8989+ println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
9090+9191+ drop(mars);
9292+ println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
9393+9494+ // TODO
9595+ drop(earth);
9696+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
9797+9898+ // TODO
9999+ drop(venus);
100100+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
101101+102102+ // TODO
103103+ drop(mercury);
104104+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
105105+106106+ assert_eq!(Rc::strong_count(&sun), 1);
107107+ }
108108+}
+10
exercises/20_threads/README.md
···11+# Threads
22+33+In most current operating systems, an executed program's code is run in a process, and the operating system manages multiple processes at once.
44+Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads.
55+66+## Further information
77+88+- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html)
99+- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html)
1010+- [Using Message Passing to Transfer Data Between Threads](https://doc.rust-lang.org/book/ch16-02-message-passing.html)
+38
exercises/20_threads/threads1.rs
···11+// This program spawns multiple threads that each runs for at least 250ms, and
22+// each thread returns how much time it took to complete. The program should
33+// wait until all the spawned threads have finished and should collect their
44+// return values into a vector.
55+66+use std::{
77+ thread,
88+ time::{Duration, Instant},
99+};
1010+1111+fn main() {
1212+ let mut handles = Vec::new();
1313+ for i in 0..10 {
1414+ let handle = thread::spawn(move || {
1515+ let start = Instant::now();
1616+ thread::sleep(Duration::from_millis(250));
1717+ println!("Thread {i} done");
1818+ start.elapsed().as_millis()
1919+ });
2020+ handles.push(handle);
2121+ }
2222+2323+ let mut results = Vec::new();
2424+ for handle in handles {
2525+ // TODO: Collect the results of all threads into the `results` vector.
2626+ // Use the `JoinHandle` struct which is returned by `thread::spawn`.
2727+ results.push(handle.join().unwrap());
2828+ }
2929+3030+ if results.len() != 10 {
3131+ panic!("Oh no! Some thread isn't done yet!");
3232+ }
3333+3434+ println!();
3535+ for (i, result) in results.into_iter().enumerate() {
3636+ println!("Thread {i} took {result}ms");
3737+ }
3838+}
+35
exercises/20_threads/threads2.rs
···11+// Building on the last exercise, we want all of the threads to complete their
22+// work. But this time, the spawned threads need to be in charge of updating a
33+// shared value: `JobStatus.jobs_done`
44+55+use std::{sync::Arc, sync::Mutex, thread, time::Duration};
66+77+struct JobStatus {
88+ jobs_done: u32,
99+}
1010+1111+fn main() {
1212+ // TODO: `Arc` isn't enough if you want a **mutable** shared state.
1313+ let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
1414+1515+ let mut handles = Vec::new();
1616+ for _ in 0..10 {
1717+ let status_shared = Arc::clone(&status);
1818+ let handle = thread::spawn(move || {
1919+ thread::sleep(Duration::from_millis(250));
2020+2121+ // TODO: You must take an action before you update a shared value.
2222+ // status_shared.jobs_done += 1;
2323+ status_shared.lock().unwrap().jobs_done += 1;
2424+ });
2525+ handles.push(handle);
2626+ }
2727+2828+ // Waiting for all jobs to complete.
2929+ for handle in handles {
3030+ handle.join().unwrap();
3131+ }
3232+3333+ // TODO: Print the value of `JobStatus.jobs_done`.
3434+ println!("Jobs done: {}", status.lock().unwrap().jobs_done);
3535+}
+61
exercises/20_threads/threads3.rs
···11+use std::{sync::mpsc, thread, time::Duration};
22+33+struct Queue {
44+ first_half: Vec<u32>,
55+ second_half: Vec<u32>,
66+}
77+88+impl Queue {
99+ fn new() -> Self {
1010+ Self {
1111+ first_half: vec![1, 2, 3, 4, 5],
1212+ second_half: vec![6, 7, 8, 9, 10],
1313+ }
1414+ }
1515+}
1616+1717+fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
1818+ // TODO: We want to send `tx` to both threads. But currently, it is moved
1919+ // into the first thread. How could you solve this problem?
2020+ let tx_clone = tx.clone();
2121+ thread::spawn(move || {
2222+ for val in q.first_half {
2323+ println!("Sending {val:?}");
2424+ tx_clone.send(val).unwrap();
2525+ thread::sleep(Duration::from_millis(250));
2626+ }
2727+ });
2828+2929+ thread::spawn(move || {
3030+ for val in q.second_half {
3131+ println!("Sending {val:?}");
3232+ tx.send(val).unwrap();
3333+ thread::sleep(Duration::from_millis(250));
3434+ }
3535+ });
3636+}
3737+3838+fn main() {
3939+ // You can optionally experiment here.
4040+}
4141+4242+#[cfg(test)]
4343+mod tests {
4444+ use super::*;
4545+4646+ #[test]
4747+ fn threads3() {
4848+ let (tx, rx) = mpsc::channel();
4949+ let queue = Queue::new();
5050+5151+ send_tx(queue, tx);
5252+5353+ let mut received = Vec::with_capacity(10);
5454+ for value in rx {
5555+ received.push(value);
5656+ }
5757+5858+ received.sort();
5959+ assert_eq!(received, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
6060+ }
6161+}
+14
exercises/21_macros/README.md
···11+# Macros
22+33+Rust's macro system is very powerful, but also kind of difficult to wrap your
44+head around. We're not going to teach you how to write your own fully-featured
55+macros. Instead, we'll show you how to use and create them.
66+77+If you'd like to learn more about writing your own macros, the
88+[macrokata](https://github.com/tfpk/macrokata) project has a similar style
99+of exercises to Rustlings, but is all about learning to write Macros.
1010+1111+## Further information
1212+1313+- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
1414+- [The Little Book of Rust Macros](https://veykril.github.io/tlborm/)
+10
exercises/21_macros/macros1.rs
···11+macro_rules! my_macro {
22+ () => {
33+ println!("Check out my macro!");
44+ };
55+}
66+77+fn main() {
88+ // TODO: Fix the macro call.
99+ my_macro!();
1010+}
+10
exercises/21_macros/macros2.rs
···11+// TODO: Fix the compiler error by moving the whole definition of this macro.
22+macro_rules! my_macro {
33+ () => {
44+ println!("Check out my macro!");
55+ };
66+}
77+88+fn main() {
99+ my_macro!();
1010+}
+17
exercises/21_macros/macros3.rs
···11+// TODO: Fix the compiler error without taking the macro definition out of this
22+// module.
33+// #[macro_use]
44+mod macros {
55+ macro_rules! my_macro {
66+ () => {
77+ println!("Check out my macro!");
88+ };
99+ }
1010+ pub(crate) use my_macro;
1111+}
1212+1313+use macros::my_macro;
1414+1515+fn main() {
1616+ my_macro!();
1717+}
+15
exercises/21_macros/macros4.rs
···11+// TODO: Fix the compiler error by adding one or two characters.
22+#[rustfmt::skip]
33+macro_rules! my_macro {
44+ () => {
55+ println!("Check out my macro!");
66+ };
77+ ($val:expr) => {
88+ println!("Look at this other macro: {}", $val);
99+ };
1010+}
1111+1212+fn main() {
1313+ my_macro!();
1414+ my_macro!(7777);
1515+}
+10
exercises/22_clippy/README.md
···11+# Clippy
22+33+The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
44+55+If you used the installation script for Rustlings, Clippy should be already installed.
66+If not you can install it manually via `rustup component add clippy`.
77+88+## Further information
99+1010+- [GitHub Repository](https://github.com/rust-lang/rust-clippy).
+15
exercises/22_clippy/clippy1.rs
···11+// The Clippy tool is a collection of lints to analyze your code so you can
22+// catch common mistakes and improve your Rust code.
33+//
44+// For these exercises, the code will fail to compile when there are Clippy
55+// warnings. Check Clippy's suggestions from the output to solve the exercise.
66+77+fn main() {
88+ // TODO: Fix the Clippy lint in this line.
99+ let pi = std::f32::consts::PI;
1010+ let radius: f32 = 5.0;
1111+1212+ let area = pi * radius.powi(2);
1313+1414+ println!("The area of a circle with radius {radius:.2} is {area:.5}");
1515+}
+10
exercises/22_clippy/clippy2.rs
···11+fn main() {
22+ let mut res = 42;
33+ let option = Some(12);
44+ // TODO: Fix the Clippy lint.
55+ if let Some(x) = option {
66+ res += x;
77+ }
88+99+ println!("{res}");
1010+}
+29
exercises/22_clippy/clippy3.rs
···11+// Here are some more easy Clippy fixes so you can see its utility 📎
22+// TODO: Fix all the Clippy lints.
33+44+#[rustfmt::skip]
55+#[allow(unused_variables, unused_assignments)]
66+fn main() {
77+ let my_option: Option<()> = None;
88+ if let Some(value) = my_option {
99+ println!("{my_option:?}");
1010+ }
1111+1212+ let my_arr = &[
1313+ -1, -2, -3,
1414+ -4, -5, -6
1515+ ];
1616+ println!("My array! Here it is: {my_arr:?}");
1717+1818+ let mut my_empty_vec = vec![1, 2, 3, 4, 5];
1919+ my_empty_vec.clear();
2020+ println!("This Vec is empty, see? {my_empty_vec:?}");
2121+2222+ let mut value_a = 45;
2323+ let mut value_b = 66;
2424+ // Let's swap these two!
2525+ // value_a = value_b;
2626+ // value_b = value_a;
2727+ std::mem::swap(&mut value_a, &mut value_b);
2828+ println!("value a: {value_a}; value b: {value_b}");
2929+}
+23
exercises/23_conversions/README.md
···11+# Type conversions
22+33+Rust offers a multitude of ways to convert a value of a given type into another type.
44+55+The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this.
66+77+Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
88+The traits are the following:
99+1010+- `From` and `Into` covered in [`from_into`](from_into.rs)
1111+- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
1212+- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
1313+1414+Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking.
1515+1616+These should be the main ways ***within the standard library*** to convert data into your desired types.
1717+1818+## Further information
1919+2020+These are not directly covered in the book, but the standard library has a great documentation for it.
2121+2222+- [conversions](https://doc.rust-lang.org/std/convert/index.html)
2323+- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
+64
exercises/23_conversions/as_ref_mut.rs
···11+// AsRef and AsMut allow for cheap reference-to-reference conversions. Read more
22+// about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html and
33+// https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
44+55+// Obtain the number of bytes (not characters) in the given argument
66+// (`.len()` returns the number of bytes in a string).
77+// TODO: Add the `AsRef` trait appropriately as a trait bound.
88+fn byte_counter<T: AsRef<str>>(arg: T) -> usize {
99+ arg.as_ref().len()
1010+}
1111+1212+// Obtain the number of characters (not bytes) in the given argument.
1313+// TODO: Add the `AsRef` trait appropriately as a trait bound.
1414+fn char_counter<T: AsRef<str>>(arg: T) -> usize {
1515+ arg.as_ref().chars().count()
1616+}
1717+1818+// Squares a number using `as_mut()`.
1919+// TODO: Add the appropriate trait bound.
2020+fn num_sq<T: AsMut<u32>>(arg: &mut T) {
2121+ // TODO: Implement the function body.
2222+ let arg = arg.as_mut();
2323+ *arg *= *arg;
2424+}
2525+2626+fn main() {
2727+ // You can optionally experiment here.
2828+}
2929+3030+#[cfg(test)]
3131+mod tests {
3232+ use super::*;
3333+3434+ #[test]
3535+ fn different_counts() {
3636+ let s = "Café au lait";
3737+ assert_ne!(char_counter(s), byte_counter(s));
3838+ }
3939+4040+ #[test]
4141+ fn same_counts() {
4242+ let s = "Cafe au lait";
4343+ assert_eq!(char_counter(s), byte_counter(s));
4444+ }
4545+4646+ #[test]
4747+ fn different_counts_using_string() {
4848+ let s = String::from("Café au lait");
4949+ assert_ne!(char_counter(s.clone()), byte_counter(s));
5050+ }
5151+5252+ #[test]
5353+ fn same_counts_using_string() {
5454+ let s = String::from("Cafe au lait");
5555+ assert_eq!(char_counter(s.clone()), byte_counter(s));
5656+ }
5757+5858+ #[test]
5959+ fn mut_box() {
6060+ let mut num: Box<u32> = Box::new(3);
6161+ num_sq(&mut num);
6262+ assert_eq!(*num, 9);
6363+ }
6464+}
+148
exercises/23_conversions/from_into.rs
···11+// The `From` trait is used for value-to-value conversions. If `From` is
22+// implemented, an implementation of `Into` is automatically provided.
33+// You can read more about it in the documentation:
44+// https://doc.rust-lang.org/std/convert/trait.From.html
55+66+#[derive(Debug)]
77+struct Person {
88+ name: String,
99+ age: u8,
1010+}
1111+1212+// We implement the Default trait to use it as a fallback when the provided
1313+// string is not convertible into a `Person` object.
1414+impl Default for Person {
1515+ fn default() -> Self {
1616+ Self {
1717+ name: String::from("John"),
1818+ age: 30,
1919+ }
2020+ }
2121+}
2222+2323+// TODO: Complete this `From` implementation to be able to parse a `Person`
2424+// out of a string in the form of "Mark,20".
2525+// Note that you'll need to parse the age component into a `u8` with something
2626+// like `"4".parse::<u8>()`.
2727+//
2828+// Steps:
2929+// 1. Split the given string on the commas present in it.
3030+// 2. If the split operation returns less or more than 2 elements, return the
3131+// default of `Person`.
3232+// 3. Use the first element from the split operation as the name.
3333+// 4. If the name is empty, return the default of `Person`.
3434+// 5. Parse the second element from the split operation into a `u8` as the age.
3535+// 6. If parsing the age fails, return the default of `Person`.
3636+impl From<&str> for Person {
3737+ fn from(s: &str) -> Self {
3838+ let mut split = s.split(',');
3939+ let (Some(name), Some(age), None) = (split.next(), split.next(), split.next()) else {
4040+ return Self::default();
4141+ };
4242+4343+ if name.is_empty() {
4444+ return Self::default();
4545+ }
4646+4747+ let Ok(age) = age.parse() else {
4848+ return Self::default();
4949+ };
5050+5151+ Self {
5252+ name: name.into(),
5353+ age,
5454+ }
5555+ }
5656+}
5757+5858+fn main() {
5959+ // Use the `from` function.
6060+ let p1 = Person::from("Mark,20");
6161+ println!("{p1:?}");
6262+6363+ // Since `From` is implemented for Person, we are able to use `Into`.
6464+ let p2: Person = "Gerald,70".into();
6565+ println!("{p2:?}");
6666+}
6767+6868+#[cfg(test)]
6969+mod tests {
7070+ use super::*;
7171+7272+ #[test]
7373+ fn test_default() {
7474+ let dp = Person::default();
7575+ assert_eq!(dp.name, "John");
7676+ assert_eq!(dp.age, 30);
7777+ }
7878+7979+ #[test]
8080+ fn test_bad_convert() {
8181+ let p = Person::from("");
8282+ assert_eq!(p.name, "John");
8383+ assert_eq!(p.age, 30);
8484+ }
8585+8686+ #[test]
8787+ fn test_good_convert() {
8888+ let p = Person::from("Mark,20");
8989+ assert_eq!(p.name, "Mark");
9090+ assert_eq!(p.age, 20);
9191+ }
9292+9393+ #[test]
9494+ fn test_bad_age() {
9595+ let p = Person::from("Mark,twenty");
9696+ assert_eq!(p.name, "John");
9797+ assert_eq!(p.age, 30);
9898+ }
9999+100100+ #[test]
101101+ fn test_missing_comma_and_age() {
102102+ let p: Person = Person::from("Mark");
103103+ assert_eq!(p.name, "John");
104104+ assert_eq!(p.age, 30);
105105+ }
106106+107107+ #[test]
108108+ fn test_missing_age() {
109109+ let p: Person = Person::from("Mark,");
110110+ assert_eq!(p.name, "John");
111111+ assert_eq!(p.age, 30);
112112+ }
113113+114114+ #[test]
115115+ fn test_missing_name() {
116116+ let p: Person = Person::from(",1");
117117+ assert_eq!(p.name, "John");
118118+ assert_eq!(p.age, 30);
119119+ }
120120+121121+ #[test]
122122+ fn test_missing_name_and_age() {
123123+ let p: Person = Person::from(",");
124124+ assert_eq!(p.name, "John");
125125+ assert_eq!(p.age, 30);
126126+ }
127127+128128+ #[test]
129129+ fn test_missing_name_and_invalid_age() {
130130+ let p: Person = Person::from(",one");
131131+ assert_eq!(p.name, "John");
132132+ assert_eq!(p.age, 30);
133133+ }
134134+135135+ #[test]
136136+ fn test_trailing_comma() {
137137+ let p: Person = Person::from("Mike,32,");
138138+ assert_eq!(p.name, "John");
139139+ assert_eq!(p.age, 30);
140140+ }
141141+142142+ #[test]
143143+ fn test_trailing_comma_and_some_string() {
144144+ let p: Person = Person::from("Mike,32,dog");
145145+ assert_eq!(p.name, "John");
146146+ assert_eq!(p.age, 30);
147147+ }
148148+}
+130
exercises/23_conversions/from_str.rs
···11+// This is similar to the previous `from_into` exercise. But this time, we'll
22+// implement `FromStr` and return errors instead of falling back to a default
33+// value. Additionally, upon implementing `FromStr`, you can use the `parse`
44+// method on strings to generate an object of the implementor type. You can read
55+// more about it in the documentation:
66+// https://doc.rust-lang.org/std/str/trait.FromStr.html
77+88+use std::num::ParseIntError;
99+use std::str::FromStr;
1010+1111+#[derive(Debug, PartialEq)]
1212+struct Person {
1313+ name: String,
1414+ age: u8,
1515+}
1616+1717+// We will use this error type for the `FromStr` implementation.
1818+#[derive(Debug, PartialEq)]
1919+enum ParsePersonError {
2020+ // Incorrect number of fields
2121+ BadLen,
2222+ // Empty name field
2323+ NoName,
2424+ // Wrapped error from parse::<u8>()
2525+ ParseInt(ParseIntError),
2626+}
2727+2828+// TODO: Complete this `FromStr` implementation to be able to parse a `Person`
2929+// out of a string in the form of "Mark,20".
3030+// Note that you'll need to parse the age component into a `u8` with something
3131+// like `"4".parse::<u8>()`.
3232+//
3333+// Steps:
3434+// 1. Split the given string on the commas present in it.
3535+// 2. If the split operation returns less or more than 2 elements, return the
3636+// error `ParsePersonError::BadLen`.
3737+// 3. Use the first element from the split operation as the name.
3838+// 4. If the name is empty, return the error `ParsePersonError::NoName`.
3939+// 5. Parse the second element from the split operation into a `u8` as the age.
4040+// 6. If parsing the age fails, return the error `ParsePersonError::ParseInt`.
4141+impl FromStr for Person {
4242+ type Err = ParsePersonError;
4343+4444+ fn from_str(s: &str) -> Result<Self, Self::Err> {
4545+ let mut split = s.split(',');
4646+4747+ let (Some(name), Some(age), None) = (split.next(), split.next(), split.next()) else {
4848+ return Err(ParsePersonError::BadLen);
4949+ };
5050+5151+ if name.is_empty() {
5252+ return Err(ParsePersonError::NoName);
5353+ }
5454+5555+ let age = age.parse().map_err(ParsePersonError::ParseInt)?;
5656+5757+ Ok(Self {
5858+ name: name.into(),
5959+ age,
6060+ })
6161+ }
6262+}
6363+6464+fn main() {
6565+ let p = "Mark,20".parse::<Person>();
6666+ println!("{p:?}");
6767+}
6868+6969+#[cfg(test)]
7070+mod tests {
7171+ use super::*;
7272+ use ParsePersonError::*;
7373+7474+ #[test]
7575+ fn empty_input() {
7676+ assert_eq!("".parse::<Person>(), Err(BadLen));
7777+ }
7878+7979+ #[test]
8080+ fn good_input() {
8181+ let p = "John,32".parse::<Person>();
8282+ assert!(p.is_ok());
8383+ let p = p.unwrap();
8484+ assert_eq!(p.name, "John");
8585+ assert_eq!(p.age, 32);
8686+ }
8787+8888+ #[test]
8989+ fn missing_age() {
9090+ assert!(matches!("John,".parse::<Person>(), Err(ParseInt(_))));
9191+ }
9292+9393+ #[test]
9494+ fn invalid_age() {
9595+ assert!(matches!("John,twenty".parse::<Person>(), Err(ParseInt(_))));
9696+ }
9797+9898+ #[test]
9999+ fn missing_comma_and_age() {
100100+ assert_eq!("John".parse::<Person>(), Err(BadLen));
101101+ }
102102+103103+ #[test]
104104+ fn missing_name() {
105105+ assert_eq!(",1".parse::<Person>(), Err(NoName));
106106+ }
107107+108108+ #[test]
109109+ fn missing_name_and_age() {
110110+ assert!(matches!(",".parse::<Person>(), Err(NoName | ParseInt(_))));
111111+ }
112112+113113+ #[test]
114114+ fn missing_name_and_invalid_age() {
115115+ assert!(matches!(
116116+ ",one".parse::<Person>(),
117117+ Err(NoName | ParseInt(_)),
118118+ ));
119119+ }
120120+121121+ #[test]
122122+ fn trailing_comma() {
123123+ assert_eq!("John,32,".parse::<Person>(), Err(BadLen));
124124+ }
125125+126126+ #[test]
127127+ fn trailing_comma_and_some_string() {
128128+ assert_eq!("John,32,man".parse::<Person>(), Err(BadLen));
129129+ }
130130+}
+197
exercises/23_conversions/try_from_into.rs
···11+// `TryFrom` is a simple and safe type conversion that may fail in a controlled
22+// way under some circumstances. Basically, this is the same as `From`. The main
33+// difference is that this should return a `Result` type instead of the target
44+// type itself. You can read more about it in the documentation:
55+// https://doc.rust-lang.org/std/convert/trait.TryFrom.html
66+77+#![allow(clippy::useless_vec)]
88+use std::convert::{TryFrom, TryInto};
99+1010+#[derive(Debug, PartialEq)]
1111+struct Color {
1212+ red: u8,
1313+ green: u8,
1414+ blue: u8,
1515+}
1616+1717+// We will use this error type for the `TryFrom` conversions.
1818+#[derive(Debug, PartialEq)]
1919+enum IntoColorError {
2020+ // Incorrect length of slice
2121+ BadLen,
2222+ // Integer conversion error
2323+ IntConversion,
2424+}
2525+2626+// TODO: Tuple implementation.
2727+// Correct RGB color values must be integers in the 0..=255 range.
2828+impl TryFrom<(i16, i16, i16)> for Color {
2929+ type Error = IntoColorError;
3030+3131+ fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
3232+ let (Ok(red), Ok(green), Ok(blue)) = (
3333+ u8::try_from(tuple.0),
3434+ u8::try_from(tuple.1),
3535+ u8::try_from(tuple.2),
3636+ ) else {
3737+ return Err(IntoColorError::IntConversion);
3838+ };
3939+4040+ Ok(Self { red, green, blue })
4141+ }
4242+}
4343+4444+// TODO: Array implementation.
4545+impl TryFrom<[i16; 3]> for Color {
4646+ type Error = IntoColorError;
4747+4848+ fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
4949+ Self::try_from((arr[0], arr[1], arr[2]))
5050+ }
5151+}
5252+5353+// TODO: Slice implementation.
5454+// This implementation needs to check the slice length.
5555+impl TryFrom<&[i16]> for Color {
5656+ type Error = IntoColorError;
5757+5858+ fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
5959+ // Check the length.
6060+ if slice.len() != 3 {
6161+ return Err(IntoColorError::BadLen);
6262+ }
6363+6464+ // Reuse the implementation for a tuple.
6565+ Self::try_from((slice[0], slice[1], slice[2]))
6666+ }
6767+}
6868+6969+fn main() {
7070+ // Using the `try_from` function.
7171+ let c1 = Color::try_from((183, 65, 14));
7272+ println!("{c1:?}");
7373+7474+ // Since `TryFrom` is implemented for `Color`, we can use `TryInto`.
7575+ let c2: Result<Color, _> = [183, 65, 14].try_into();
7676+ println!("{c2:?}");
7777+7878+ let v = vec![183, 65, 14];
7979+ // With slice we should use the `try_from` function
8080+ let c3 = Color::try_from(&v[..]);
8181+ println!("{c3:?}");
8282+ // or put the slice within round brackets and use `try_into`.
8383+ let c4: Result<Color, _> = (&v[..]).try_into();
8484+ println!("{c4:?}");
8585+}
8686+8787+#[cfg(test)]
8888+mod tests {
8989+ use super::*;
9090+ use IntoColorError::*;
9191+9292+ #[test]
9393+ fn test_tuple_out_of_range_positive() {
9494+ assert_eq!(Color::try_from((256, 1000, 10000)), Err(IntConversion));
9595+ }
9696+9797+ #[test]
9898+ fn test_tuple_out_of_range_negative() {
9999+ assert_eq!(Color::try_from((-1, -10, -256)), Err(IntConversion));
100100+ }
101101+102102+ #[test]
103103+ fn test_tuple_sum() {
104104+ assert_eq!(Color::try_from((-1, 255, 255)), Err(IntConversion));
105105+ }
106106+107107+ #[test]
108108+ fn test_tuple_correct() {
109109+ let c: Result<Color, _> = (183, 65, 14).try_into();
110110+ assert!(c.is_ok());
111111+ assert_eq!(
112112+ c.unwrap(),
113113+ Color {
114114+ red: 183,
115115+ green: 65,
116116+ blue: 14,
117117+ }
118118+ );
119119+ }
120120+121121+ #[test]
122122+ fn test_array_out_of_range_positive() {
123123+ let c: Result<Color, _> = [1000, 10000, 256].try_into();
124124+ assert_eq!(c, Err(IntConversion));
125125+ }
126126+127127+ #[test]
128128+ fn test_array_out_of_range_negative() {
129129+ let c: Result<Color, _> = [-10, -256, -1].try_into();
130130+ assert_eq!(c, Err(IntConversion));
131131+ }
132132+133133+ #[test]
134134+ fn test_array_sum() {
135135+ let c: Result<Color, _> = [-1, 255, 255].try_into();
136136+ assert_eq!(c, Err(IntConversion));
137137+ }
138138+139139+ #[test]
140140+ fn test_array_correct() {
141141+ let c: Result<Color, _> = [183, 65, 14].try_into();
142142+ assert!(c.is_ok());
143143+ assert_eq!(
144144+ c.unwrap(),
145145+ Color {
146146+ red: 183,
147147+ green: 65,
148148+ blue: 14
149149+ }
150150+ );
151151+ }
152152+153153+ #[test]
154154+ fn test_slice_out_of_range_positive() {
155155+ let arr = [10000, 256, 1000];
156156+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
157157+ }
158158+159159+ #[test]
160160+ fn test_slice_out_of_range_negative() {
161161+ let arr = [-256, -1, -10];
162162+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
163163+ }
164164+165165+ #[test]
166166+ fn test_slice_sum() {
167167+ let arr = [-1, 255, 255];
168168+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
169169+ }
170170+171171+ #[test]
172172+ fn test_slice_correct() {
173173+ let v = vec![183, 65, 14];
174174+ let c: Result<Color, _> = Color::try_from(&v[..]);
175175+ assert!(c.is_ok());
176176+ assert_eq!(
177177+ c.unwrap(),
178178+ Color {
179179+ red: 183,
180180+ green: 65,
181181+ blue: 14,
182182+ }
183183+ );
184184+ }
185185+186186+ #[test]
187187+ fn test_slice_excess_length() {
188188+ let v = vec![0, 0, 0, 0];
189189+ assert_eq!(Color::try_from(&v[..]), Err(BadLen));
190190+ }
191191+192192+ #[test]
193193+ fn test_slice_insufficient_length() {
194194+ let v = vec![0, 0];
195195+ assert_eq!(Color::try_from(&v[..]), Err(BadLen));
196196+ }
197197+}
+24
exercises/23_conversions/using_as.rs
···11+// Type casting in Rust is done via the usage of the `as` operator.
22+// Note that the `as` operator is not only used when type casting. It also helps
33+// with renaming imports.
44+55+fn average(values: &[f64]) -> f64 {
66+ let total = values.iter().sum::<f64>();
77+ // TODO: Make a conversion before dividing.
88+ total / values.len() as f64
99+}
1010+1111+fn main() {
1212+ let values = [3.5, 0.3, 13.0, 11.7];
1313+ println!("{}", average(&values));
1414+}
1515+1616+#[cfg(test)]
1717+mod tests {
1818+ use super::*;
1919+2020+ #[test]
2121+ fn returns_proper_type_and_value() {
2222+ assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
2323+ }
2424+}
···11+# Quizzes
22+33+After every couple of sections, there will be a quiz in this directory that'll test your knowledge on a bunch of sections at once.
+39
exercises/quizzes/quiz1.rs
···11+// This is a quiz for the following sections:
22+// - Variables
33+// - Functions
44+// - If
55+//
66+// Mary is buying apples. The price of an apple is calculated as follows:
77+// - An apple costs 2 rustbucks.
88+// - However, if Mary buys more than 40 apples, the price of each apple in the
99+// entire order is reduced to only 1 rustbuck!
1010+1111+// TODO: Write a function that calculates the price of an order of apples given
1212+// the quantity bought.
1313+// fn calculate_price_of_apples(???) -> ??? { ??? }
1414+1515+fn calculate_price_of_apples(num: i32) -> i32 {
1616+ if num > 40 {
1717+ num
1818+ } else {
1919+ num * 2
2020+ }
2121+}
2222+2323+fn main() {
2424+ // You can optionally experiment here.
2525+}
2626+2727+// Don't change the tests!
2828+#[cfg(test)]
2929+mod tests {
3030+ use super::*;
3131+3232+ #[test]
3333+ fn verify_test() {
3434+ assert_eq!(calculate_price_of_apples(35), 70);
3535+ assert_eq!(calculate_price_of_apples(40), 80);
3636+ assert_eq!(calculate_price_of_apples(41), 41);
3737+ assert_eq!(calculate_price_of_apples(65), 65);
3838+ }
3939+}
+81
exercises/quizzes/quiz2.rs
···11+// This is a quiz for the following sections:
22+// - Strings
33+// - Vecs
44+// - Move semantics
55+// - Modules
66+// - Enums
77+//
88+// Let's build a little machine in the form of a function. As input, we're going
99+// to give a list of strings and commands. These commands determine what action
1010+// is going to be applied to the string. It can either be:
1111+// - Uppercase the string
1212+// - Trim the string
1313+// - Append "bar" to the string a specified amount of times
1414+//
1515+// The exact form of this will be:
1616+// - The input is going to be a Vector of 2-length tuples,
1717+// the first element is the string, the second one is the command.
1818+// - The output element is going to be a vector of strings.
1919+2020+enum Command {
2121+ Uppercase,
2222+ Trim,
2323+ Append(usize),
2424+}
2525+2626+mod my_module {
2727+ use super::Command;
2828+2929+ // TODO: Complete the function as described above.
3030+ // pub fn transformer(input: ???) -> ??? { ??? }
3131+ pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
3232+ let mut result = vec![];
3333+ for data in &input {
3434+ match data.1 {
3535+ Command::Uppercase => {
3636+ result.push(data.0.to_uppercase());
3737+ }
3838+ Command::Trim => {
3939+ result.push(data.0.trim().to_string());
4040+ }
4141+ Command::Append(n) => {
4242+ result.push(format!("{}{}", data.0, "bar".repeat(n)));
4343+ }
4444+ }
4545+ }
4646+ result
4747+ }
4848+}
4949+5050+fn main() {
5151+ // You can optionally experiment here.
5252+}
5353+5454+#[cfg(test)]
5555+mod tests {
5656+ // TODO: What do we need to import to have `transformer` in scope?
5757+ // use ???;
5858+ use super::Command;
5959+ use crate::my_module::transformer;
6060+6161+ #[test]
6262+ fn it_works() {
6363+ let input = vec![
6464+ ("hello".to_string(), Command::Uppercase),
6565+ (" all roads lead to rome! ".to_string(), Command::Trim),
6666+ ("foo".to_string(), Command::Append(1)),
6767+ ("bar".to_string(), Command::Append(5)),
6868+ ];
6969+ let output = transformer(input);
7070+7171+ assert_eq!(
7272+ output,
7373+ [
7474+ "HELLO",
7575+ "all roads lead to rome!",
7676+ "foobar",
7777+ "barbarbarbarbarbar",
7878+ ]
7979+ );
8080+ }
8181+}
+65
exercises/quizzes/quiz3.rs
···11+// This quiz tests:
22+// - Generics
33+// - Traits
44+//
55+// An imaginary magical school has a new report card generation system written
66+// in Rust! Currently, the system only supports creating report cards where the
77+// student's grade is represented numerically (e.g. 1.0 -> 5.5). However, the
88+// school also issues alphabetical grades (A+ -> F-) and needs to be able to
99+// print both types of report card!
1010+//
1111+// Make the necessary code changes in the struct `ReportCard` and the impl
1212+// block to support alphabetical report cards in addition to numerical ones.
1313+use std::fmt::Display;
1414+1515+// TODO: Adjust the struct as described above.
1616+struct ReportCard<T> {
1717+ grade: T,
1818+ student_name: String,
1919+ student_age: u8,
2020+}
2121+2222+// TODO: Adjust the impl block as described above.
2323+impl<T: Display> ReportCard<T> {
2424+ fn print(&self) -> String {
2525+ format!(
2626+ "{} ({}) - achieved a grade of {}",
2727+ &self.student_name, &self.student_age, &self.grade,
2828+ )
2929+ }
3030+}
3131+3232+fn main() {
3333+ // You can optionally experiment here.
3434+}
3535+3636+#[cfg(test)]
3737+mod tests {
3838+ use super::*;
3939+4040+ #[test]
4141+ fn generate_numeric_report_card() {
4242+ let report_card = ReportCard {
4343+ grade: 2.1,
4444+ student_name: "Tom Wriggle".to_string(),
4545+ student_age: 12,
4646+ };
4747+ assert_eq!(
4848+ report_card.print(),
4949+ "Tom Wriggle (12) - achieved a grade of 2.1",
5050+ );
5151+ }
5252+5353+ #[test]
5454+ fn generate_alphabetic_report_card() {
5555+ let report_card = ReportCard {
5656+ grade: "A+",
5757+ student_name: "Gary Plotter".to_string(),
5858+ student_age: 11,
5959+ };
6060+ assert_eq!(
6161+ report_card.print(),
6262+ "Gary Plotter (11) - achieved a grade of A+",
6363+ );
6464+ }
6565+}
···11+fn main() {
22+ // Congratulations, you finished the first exercise 🎉
33+ // As an introduction to Rustlings, the first exercise only required
44+ // entering `n` in the terminal to go to the next exercise.
55+}
···11+fn main() {
22+ // Declaring variables requires the `let` keyword.
33+ let x = 5;
44+55+ println!("x has the value {x}");
66+}
+16
solutions/01_variables/variables2.rs
···11+fn main() {
22+ // The easiest way to fix the compiler error is to initialize the
33+ // variable `x`. By setting its value to an integer, Rust infers its type
44+ // as `i32` which is the default type for integers.
55+ let x = 42;
66+77+ // But we can enforce a type different from the default `i32` by adding
88+ // a type annotation:
99+ // let x: u8 = 42;
1010+1111+ if x == 10 {
1212+ println!("x is ten!");
1313+ } else {
1414+ println!("x is not ten!");
1515+ }
1616+}
+15
solutions/01_variables/variables3.rs
···11+#![allow(clippy::needless_late_init)]
22+33+fn main() {
44+ // Reading uninitialized variables isn't allowed in Rust!
55+ // Therefore, we need to assign a value first.
66+ let x: i32 = 42;
77+88+ println!("Number {x}");
99+1010+ // It is possible to declare a variable and initialize it later.
1111+ // But it can't be used before initialization.
1212+ let y: i32;
1313+ y = 42;
1414+ println!("Number {y}");
1515+}
+9
solutions/01_variables/variables4.rs
···11+fn main() {
22+ // In Rust, variables are immutable by default.
33+ // Adding the `mut` keyword after `let` makes the declared variable mutable.
44+ let mut x = 3;
55+ println!("Number {x}");
66+77+ x = 5;
88+ println!("Number {x}");
99+}
+9
solutions/01_variables/variables5.rs
···11+fn main() {
22+ let number = "T-H-R-E-E";
33+ println!("Spell a number: {}", number);
44+55+ // Using variable shadowing
66+ // https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
77+ let number = 3;
88+ println!("Number plus two is: {}", number + 2);
99+}
+6
solutions/01_variables/variables6.rs
···11+// The type of constants must always be annotated.
22+const NUMBER: u64 = 3;
33+44+fn main() {
55+ println!("Number: {NUMBER}");
66+}
+8
solutions/02_functions/functions1.rs
···11+// Some function with the name `call_me` without arguments or a return value.
22+fn call_me() {
33+ println!("Hello world!");
44+}
55+66+fn main() {
77+ call_me();
88+}
+11
solutions/02_functions/functions2.rs
···11+// The type of function arguments must be annotated.
22+// Added the type annotation `u64`.
33+fn call_me(num: u64) {
44+ for i in 0..num {
55+ println!("Ring! Call number {}", i + 1);
66+ }
77+}
88+99+fn main() {
1010+ call_me(3);
1111+}
+10
solutions/02_functions/functions3.rs
···11+fn call_me(num: u8) {
22+ for i in 0..num {
33+ println!("Ring! Call number {}", i + 1);
44+ }
55+}
66+77+fn main() {
88+ // `call_me` expects an argument.
99+ call_me(5);
1010+}
+17
solutions/02_functions/functions4.rs
···11+fn is_even(num: i64) -> bool {
22+ num % 2 == 0
33+}
44+55+// The return type must always be annotated.
66+fn sale_price(price: i64) -> i64 {
77+ if is_even(price) {
88+ price - 10
99+ } else {
1010+ price - 3
1111+ }
1212+}
1313+1414+fn main() {
1515+ let original_price = 51;
1616+ println!("Your sale price is {}", sale_price(original_price));
1717+}
+9
solutions/02_functions/functions5.rs
···11+fn square(num: i32) -> i32 {
22+ // Removed the semicolon `;` at the end of the line below to implicitly return the result.
33+ num * num
44+}
55+66+fn main() {
77+ let answer = square(3);
88+ println!("The square of 3 is {answer}");
99+}
+32
solutions/03_if/if1.rs
···11+fn bigger(a: i32, b: i32) -> i32 {
22+ if a > b {
33+ a
44+ } else {
55+ b
66+ }
77+}
88+99+fn main() {
1010+ // You can optionally experiment here.
1111+}
1212+1313+// Don't mind this for now :)
1414+#[cfg(test)]
1515+mod tests {
1616+ use super::*;
1717+1818+ #[test]
1919+ fn ten_is_bigger_than_eight() {
2020+ assert_eq!(10, bigger(10, 8));
2121+ }
2222+2323+ #[test]
2424+ fn fortytwo_is_bigger_than_thirtytwo() {
2525+ assert_eq!(42, bigger(32, 42));
2626+ }
2727+2828+ #[test]
2929+ fn equal_numbers() {
3030+ assert_eq!(42, bigger(42, 42));
3131+ }
3232+}
+35
solutions/03_if/if2.rs
···11+fn picky_eater(food: &str) -> &str {
22+ if food == "strawberry" {
33+ "Yummy!"
44+ } else if food == "potato" {
55+ "I guess I can eat that."
66+ } else {
77+ "No thanks!"
88+ }
99+}
1010+1111+fn main() {
1212+ // You can optionally experiment here.
1313+}
1414+1515+#[cfg(test)]
1616+mod tests {
1717+ use super::*;
1818+1919+ #[test]
2020+ fn yummy_food() {
2121+ assert_eq!(picky_eater("strawberry"), "Yummy!");
2222+ }
2323+2424+ #[test]
2525+ fn neutral_food() {
2626+ assert_eq!(picky_eater("potato"), "I guess I can eat that.");
2727+ }
2828+2929+ #[test]
3030+ fn default_disliked_food() {
3131+ assert_eq!(picky_eater("broccoli"), "No thanks!");
3232+ assert_eq!(picky_eater("gummy bears"), "No thanks!");
3333+ assert_eq!(picky_eater("literally anything"), "No thanks!");
3434+ }
3535+}
+53
solutions/03_if/if3.rs
···11+fn animal_habitat(animal: &str) -> &str {
22+ let identifier = if animal == "crab" {
33+ 1
44+ } else if animal == "gopher" {
55+ 2
66+ } else if animal == "snake" {
77+ 3
88+ } else {
99+ // Any unused identifier.
1010+ 4
1111+ };
1212+1313+ // Instead of such an identifier, you would use an enum in Rust.
1414+ // But we didn't get into enums yet.
1515+ if identifier == 1 {
1616+ "Beach"
1717+ } else if identifier == 2 {
1818+ "Burrow"
1919+ } else if identifier == 3 {
2020+ "Desert"
2121+ } else {
2222+ "Unknown"
2323+ }
2424+}
2525+2626+fn main() {
2727+ // You can optionally experiment here.
2828+}
2929+3030+#[cfg(test)]
3131+mod tests {
3232+ use super::*;
3333+3434+ #[test]
3535+ fn gopher_lives_in_burrow() {
3636+ assert_eq!(animal_habitat("gopher"), "Burrow")
3737+ }
3838+3939+ #[test]
4040+ fn snake_lives_in_desert() {
4141+ assert_eq!(animal_habitat("snake"), "Desert")
4242+ }
4343+4444+ #[test]
4545+ fn crab_lives_on_beach() {
4646+ assert_eq!(animal_habitat("crab"), "Beach")
4747+ }
4848+4949+ #[test]
5050+ fn unknown_animal() {
5151+ assert_eq!(animal_habitat("dinosaur"), "Unknown")
5252+ }
5353+}
+11
solutions/04_primitive_types/primitive_types1.rs
···11+fn main() {
22+ let is_morning = true;
33+ if is_morning {
44+ println!("Good morning!");
55+ }
66+77+ let is_evening = !is_morning;
88+ if is_evening {
99+ println!("Good evening!");
1010+ }
1111+}
+21
solutions/04_primitive_types/primitive_types2.rs
···11+fn main() {
22+ let my_first_initial = 'C';
33+ if my_first_initial.is_alphabetic() {
44+ println!("Alphabetical!");
55+ } else if my_first_initial.is_numeric() {
66+ println!("Numerical!");
77+ } else {
88+ println!("Neither alphabetic nor numeric!");
99+ }
1010+1111+ // Example with an emoji.
1212+ let your_character = '🦀';
1313+1414+ if your_character.is_alphabetic() {
1515+ println!("Alphabetical!");
1616+ } else if your_character.is_numeric() {
1717+ println!("Numerical!");
1818+ } else {
1919+ println!("Neither alphabetic nor numeric!");
2020+ }
2121+}
+11
solutions/04_primitive_types/primitive_types3.rs
···11+fn main() {
22+ // An array with 100 elements of the value 42.
33+ let a = [42; 100];
44+55+ if a.len() >= 100 {
66+ println!("Wow, that's a big array!");
77+ } else {
88+ println!("Meh, I eat arrays like that for breakfast.");
99+ panic!("Array not big enough, more elements needed");
1010+ }
1111+}
+23
solutions/04_primitive_types/primitive_types4.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ #[test]
88+ fn slice_out_of_array() {
99+ let a = [1, 2, 3, 4, 5];
1010+ // 0 1 2 3 4 <- indices
1111+ // -------
1212+ // |
1313+ // +--- slice
1414+1515+ // Note that the upper index 4 is excluded.
1616+ let nice_slice = &a[1..4];
1717+ assert_eq!([2, 3, 4], nice_slice);
1818+1919+ // The upper index can be included by using the syntax `..=` (with `=` sign)
2020+ let nice_slice = &a[1..=3];
2121+ assert_eq!([2, 3, 4], nice_slice);
2222+ }
2323+}
+8
solutions/04_primitive_types/primitive_types5.rs
···11+fn main() {
22+ let cat = ("Furry McFurson", 3.5);
33+44+ // Destructuring the tuple.
55+ let (name, age) = cat;
66+77+ println!("{name} is {age} years old");
88+}
+16
solutions/04_primitive_types/primitive_types6.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ #[test]
88+ fn indexing_tuple() {
99+ let numbers = (1, 2, 3);
1010+1111+ // Tuple indexing syntax.
1212+ let second = numbers.1;
1313+1414+ assert_eq!(second, 2, "This is not the 2nd number in the tuple!");
1515+ }
1616+}
+23
solutions/05_vecs/vecs1.rs
···11+fn array_and_vec() -> ([i32; 4], Vec<i32>) {
22+ let a = [10, 20, 30, 40]; // Array
33+44+ // Used the `vec!` macro.
55+ let v = vec![10, 20, 30, 40];
66+77+ (a, v)
88+}
99+1010+fn main() {
1111+ // You can optionally experiment here.
1212+}
1313+1414+#[cfg(test)]
1515+mod tests {
1616+ use super::*;
1717+1818+ #[test]
1919+ fn test_array_and_vec_similarity() {
2020+ let (a, v) = array_and_vec();
2121+ assert_eq!(a, *v);
2222+ }
2323+}
+55
solutions/05_vecs/vecs2.rs
···11+fn vec_loop(input: &[i32]) -> Vec<i32> {
22+ let mut output = Vec::new();
33+44+ for element in input {
55+ output.push(2 * element);
66+ }
77+88+ output
99+}
1010+1111+fn vec_map_example(input: &[i32]) -> Vec<i32> {
1212+ // An example of collecting a vector after mapping.
1313+ // We map each element of the `input` slice to its value plus 1.
1414+ // If the input is `[1, 2, 3]`, the output is `[2, 3, 4]`.
1515+ input.iter().map(|element| element + 1).collect()
1616+}
1717+1818+fn vec_map(input: &[i32]) -> Vec<i32> {
1919+ // We will dive deeper into iterators, but for now, this is all what you
2020+ // had to do!
2121+ // Advanced note: This method is more efficient because it automatically
2222+ // preallocates enough capacity. This can be done manually in `vec_loop`
2323+ // using `Vec::with_capacity(input.len())` instead of `Vec::new()`.
2424+ input.iter().map(|element| 2 * element).collect()
2525+}
2626+2727+fn main() {
2828+ // You can optionally experiment here.
2929+}
3030+3131+#[cfg(test)]
3232+mod tests {
3333+ use super::*;
3434+3535+ #[test]
3636+ fn test_vec_loop() {
3737+ let input = [2, 4, 6, 8, 10];
3838+ let ans = vec_loop(&input);
3939+ assert_eq!(ans, [4, 8, 12, 16, 20]);
4040+ }
4141+4242+ #[test]
4343+ fn test_vec_map_example() {
4444+ let input = [1, 2, 3];
4545+ let ans = vec_map_example(&input);
4646+ assert_eq!(ans, [2, 3, 4]);
4747+ }
4848+4949+ #[test]
5050+ fn test_vec_map() {
5151+ let input = [2, 4, 6, 8, 10];
5252+ let ans = vec_map(&input);
5353+ assert_eq!(ans, [4, 8, 12, 16, 20]);
5454+ }
5555+}
+25
solutions/06_move_semantics/move_semantics1.rs
···11+fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
22+ let mut vec = vec;
33+ // ^^^ added
44+55+ vec.push(88);
66+77+ vec
88+}
99+1010+fn main() {
1111+ // You can optionally experiment here.
1212+}
1313+1414+#[cfg(test)]
1515+mod tests {
1616+ use super::*;
1717+1818+ #[test]
1919+ fn move_semantics1() {
2020+ let vec0 = vec![22, 44, 66];
2121+ let vec1 = fill_vec(vec0);
2222+ // `vec0` can't be accessed anymore because it is moved to `fill_vec`.
2323+ assert_eq!(vec1, vec![22, 44, 66, 88]);
2424+ }
2525+}
+28
solutions/06_move_semantics/move_semantics2.rs
···11+fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
22+ let mut vec = vec;
33+44+ vec.push(88);
55+66+ vec
77+}
88+99+fn main() {
1010+ // You can optionally experiment here.
1111+}
1212+1313+#[cfg(test)]
1414+mod tests {
1515+ use super::*;
1616+1717+ #[test]
1818+ fn move_semantics2() {
1919+ let vec0 = vec![22, 44, 66];
2020+2121+ // Cloning `vec0` so that the clone is moved into `fill_vec`, not `vec0`
2222+ // itself.
2323+ let vec1 = fill_vec(vec0.clone());
2424+2525+ assert_eq!(vec0, [22, 44, 66]);
2626+ assert_eq!(vec1, [22, 44, 66, 88]);
2727+ }
2828+}
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ // TODO: Fix the compiler errors only by reordering the lines in the test.
88+ // Don't add, change or remove any line.
99+ #[test]
1010+ fn move_semantics4() {
1111+ let mut x = Vec::new();
1212+ let y = &mut x;
1313+ // `y` used here.
1414+ y.push(42);
1515+ // The mutable reference `y` is not used anymore,
1616+ // therefore a new reference can be created.
1717+ let z = &mut x;
1818+ z.push(13);
1919+ assert_eq!(x, [42, 13]);
2020+ }
2121+}
+23
solutions/06_move_semantics/move_semantics5.rs
···11+#![allow(clippy::ptr_arg)]
22+33+// Borrows instead of taking ownership.
44+// It is recommended to use `&str` instead of `&String` here. But this is
55+// enough for now because we didn't handle strings yet.
66+fn get_char(data: &String) -> char {
77+ data.chars().last().unwrap()
88+}
99+1010+// Takes ownership instead of borrowing.
1111+fn string_uppercase(mut data: String) {
1212+ data = data.to_uppercase();
1313+1414+ println!("{data}");
1515+}
1616+1717+fn main() {
1818+ let data = "Rust is great!".to_string();
1919+2020+ get_char(&data);
2121+2222+ string_uppercase(data);
2323+}
···11+fn current_favorite_color() -> String {
22+ // Equivalent to `String::from("blue")`
33+ "blue".to_string()
44+}
55+66+fn main() {
77+ let answer = current_favorite_color();
88+ println!("My current favorite color is {answer}");
99+}
+15
solutions/09_strings/strings2.rs
···11+fn is_a_color_word(attempt: &str) -> bool {
22+ attempt == "green" || attempt == "blue" || attempt == "red"
33+}
44+55+fn main() {
66+ let word = String::from("green");
77+88+ if is_a_color_word(&word) {
99+ // ^ added to have `&String` which is automatically
1010+ // coerced to `&str` by the compiler.
1111+ println!("That is a color word I know!");
1212+ } else {
1313+ println!("That is not a color word I know.");
1414+ }
1515+}
+48
solutions/09_strings/strings3.rs
···11+fn trim_me(input: &str) -> &str {
22+ input.trim()
33+}
44+55+fn compose_me(input: &str) -> String {
66+ // The macro `format!` has the same syntax as `println!`, but it returns a
77+ // string instead of printing it to the terminal.
88+ // Equivalent to `input.to_string() + " world!"`
99+ format!("{input} world!")
1010+}
1111+1212+fn replace_me(input: &str) -> String {
1313+ input.replace("cars", "balloons")
1414+}
1515+1616+fn main() {
1717+ // You can optionally experiment here.
1818+}
1919+2020+#[cfg(test)]
2121+mod tests {
2222+ use super::*;
2323+2424+ #[test]
2525+ fn trim_a_string() {
2626+ assert_eq!(trim_me("Hello! "), "Hello!");
2727+ assert_eq!(trim_me(" What's up!"), "What's up!");
2828+ assert_eq!(trim_me(" Hola! "), "Hola!");
2929+ }
3030+3131+ #[test]
3232+ fn compose_a_string() {
3333+ assert_eq!(compose_me("Hello"), "Hello world!");
3434+ assert_eq!(compose_me("Goodbye"), "Goodbye world!");
3535+ }
3636+3737+ #[test]
3838+ fn replace_a_string() {
3939+ assert_eq!(
4040+ replace_me("I think cars are cool"),
4141+ "I think balloons are cool",
4242+ );
4343+ assert_eq!(
4444+ replace_me("I love to look at cars"),
4545+ "I love to look at balloons",
4646+ );
4747+ }
4848+}
+38
solutions/09_strings/strings4.rs
···11+fn string_slice(arg: &str) {
22+ println!("{arg}");
33+}
44+55+fn string(arg: String) {
66+ println!("{arg}");
77+}
88+99+fn main() {
1010+ string_slice("blue");
1111+1212+ string("red".to_string());
1313+1414+ string(String::from("hi"));
1515+1616+ string("rust is fun!".to_owned());
1717+1818+ // Here, both answers work.
1919+ // `.into()` converts a type into an expected type.
2020+ // If it is called where `String` is expected, it will convert `&str` to `String`.
2121+ string("nice weather".into());
2222+ // But if it is called where `&str` is expected, then `&str` is kept `&str` since no conversion is needed.
2323+ // If you remove the `#[allow(…)]` line, then Clippy will tell you to remove `.into()` below since it is a useless conversion.
2424+ #[allow(clippy::useless_conversion)]
2525+ string_slice("nice weather".into());
2626+2727+ string(format!("Interpolation {}", "Station"));
2828+2929+ // WARNING: This is byte indexing, not character indexing.
3030+ // Character indexing can be done using `s.chars().nth(INDEX)`.
3131+ string_slice(&String::from("abc")[0..1]);
3232+3333+ string_slice(" hello there ".trim());
3434+3535+ string("Happy Monday!".replace("Mon", "Tues"));
3636+3737+ string("mY sHiFt KeY iS sTiCkY".to_lowercase());
3838+}
+15
solutions/10_modules/modules1.rs
···11+mod sausage_factory {
22+ fn get_secret_recipe() -> String {
33+ String::from("Ginger")
44+ }
55+66+ // Added `pub` before `fn` to make the function accessible outside the module.
77+ pub fn make_sausage() {
88+ get_secret_recipe();
99+ println!("sausage!");
1010+ }
1111+}
1212+1313+fn main() {
1414+ sausage_factory::make_sausage();
1515+}
+23
solutions/10_modules/modules2.rs
···11+mod delicious_snacks {
22+ // Added `pub` and used the expected alias after `as`.
33+ pub use self::fruits::PEAR as fruit;
44+ pub use self::veggies::CUCUMBER as veggie;
55+66+ mod fruits {
77+ pub const PEAR: &str = "Pear";
88+ pub const APPLE: &str = "Apple";
99+ }
1010+1111+ mod veggies {
1212+ pub const CUCUMBER: &str = "Cucumber";
1313+ pub const CARROT: &str = "Carrot";
1414+ }
1515+}
1616+1717+fn main() {
1818+ println!(
1919+ "favorite snacks: {} and {}",
2020+ delicious_snacks::fruit,
2121+ delicious_snacks::veggie,
2222+ );
2323+}
+8
solutions/10_modules/modules3.rs
···11+use std::time::{SystemTime, UNIX_EPOCH};
22+33+fn main() {
44+ match SystemTime::now().duration_since(UNIX_EPOCH) {
55+ Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
66+ Err(_) => panic!("SystemTime before UNIX EPOCH!"),
77+ }
88+}
+42
solutions/11_hashmaps/hashmaps1.rs
···11+// A basket of fruits in the form of a hash map needs to be defined. The key
22+// represents the name of the fruit and the value represents how many of that
33+// particular fruit is in the basket. You have to put at least 3 different
44+// types of fruits (e.g apple, banana, mango) in the basket and the total count
55+// of all the fruits should be at least 5.
66+77+use std::collections::HashMap;
88+99+fn fruit_basket() -> HashMap<String, u32> {
1010+ // Declare the hash map.
1111+ let mut basket = HashMap::new();
1212+1313+ // Two bananas are already given for you :)
1414+ basket.insert(String::from("banana"), 2);
1515+1616+ // Put more fruits in your basket.
1717+ basket.insert(String::from("apple"), 3);
1818+ basket.insert(String::from("mango"), 1);
1919+2020+ basket
2121+}
2222+2323+fn main() {
2424+ // You can optionally experiment here.
2525+}
2626+2727+#[cfg(test)]
2828+mod tests {
2929+ use super::*;
3030+3131+ #[test]
3232+ fn at_least_three_types_of_fruits() {
3333+ let basket = fruit_basket();
3434+ assert!(basket.len() >= 3);
3535+ }
3636+3737+ #[test]
3838+ fn at_least_five_fruits() {
3939+ let basket = fruit_basket();
4040+ assert!(basket.values().sum::<u32>() >= 5);
4141+ }
4242+}
+96
solutions/11_hashmaps/hashmaps2.rs
···11+// We're collecting different fruits to bake a delicious fruit cake. For this,
22+// we have a basket, which we'll represent in the form of a hash map. The key
33+// represents the name of each fruit we collect and the value represents how
44+// many of that particular fruit we have collected. Three types of fruits -
55+// Apple (4), Mango (2) and Lychee (5) are already in the basket hash map. You
66+// must add fruit to the basket so that there is at least one of each kind and
77+// more than 11 in total - we have a lot of mouths to feed. You are not allowed
88+// to insert any more of the fruits that are already in the basket (Apple,
99+// Mango, and Lychee).
1010+1111+use std::collections::HashMap;
1212+1313+#[derive(Hash, PartialEq, Eq, Debug)]
1414+enum Fruit {
1515+ Apple,
1616+ Banana,
1717+ Mango,
1818+ Lychee,
1919+ Pineapple,
2020+}
2121+2222+fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
2323+ let fruit_kinds = [
2424+ Fruit::Apple,
2525+ Fruit::Banana,
2626+ Fruit::Mango,
2727+ Fruit::Lychee,
2828+ Fruit::Pineapple,
2929+ ];
3030+3131+ for fruit in fruit_kinds {
3232+ // If fruit doesn't exist, insert it with some value.
3333+ basket.entry(fruit).or_insert(5);
3434+ }
3535+}
3636+3737+fn main() {
3838+ // You can optionally experiment here.
3939+}
4040+4141+#[cfg(test)]
4242+mod tests {
4343+ use super::*;
4444+4545+ // Don't modify this function!
4646+ fn get_fruit_basket() -> HashMap<Fruit, u32> {
4747+ let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
4848+ HashMap::from_iter(content)
4949+ }
5050+5151+ #[test]
5252+ fn test_given_fruits_are_not_modified() {
5353+ let mut basket = get_fruit_basket();
5454+ fruit_basket(&mut basket);
5555+ assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
5656+ assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
5757+ assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
5858+ }
5959+6060+ #[test]
6161+ fn at_least_five_types_of_fruits() {
6262+ let mut basket = get_fruit_basket();
6363+ fruit_basket(&mut basket);
6464+ let count_fruit_kinds = basket.len();
6565+ assert!(count_fruit_kinds >= 5);
6666+ }
6767+6868+ #[test]
6969+ fn greater_than_eleven_fruits() {
7070+ let mut basket = get_fruit_basket();
7171+ fruit_basket(&mut basket);
7272+ let count = basket.values().sum::<u32>();
7373+ assert!(count > 11);
7474+ }
7575+7676+ #[test]
7777+ fn all_fruit_types_in_basket() {
7878+ let fruit_kinds = [
7979+ Fruit::Apple,
8080+ Fruit::Banana,
8181+ Fruit::Mango,
8282+ Fruit::Lychee,
8383+ Fruit::Pineapple,
8484+ ];
8585+8686+ let mut basket = get_fruit_basket();
8787+ fruit_basket(&mut basket);
8888+8989+ for fruit_kind in fruit_kinds {
9090+ let Some(amount) = basket.get(&fruit_kind) else {
9191+ panic!("Fruit kind {fruit_kind:?} was not found in basket");
9292+ };
9393+ assert!(*amount > 0);
9494+ }
9595+ }
9696+}
+83
solutions/11_hashmaps/hashmaps3.rs
···11+// A list of scores (one per line) of a soccer match is given. Each line is of
22+// the form "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>"
33+// Example: "England,France,4,2" (England scored 4 goals, France 2).
44+//
55+// You have to build a scores table containing the name of the team, the total
66+// number of goals the team scored, and the total number of goals the team
77+// conceded.
88+99+use std::collections::HashMap;
1010+1111+// A structure to store the goal details of a team.
1212+#[derive(Default)]
1313+struct TeamScores {
1414+ goals_scored: u8,
1515+ goals_conceded: u8,
1616+}
1717+1818+fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
1919+ // The name of the team is the key and its associated struct is the value.
2020+ let mut scores = HashMap::<&str, TeamScores>::new();
2121+2222+ for line in results.lines() {
2323+ let mut split_iterator = line.split(',');
2424+ // NOTE: We use `unwrap` because we didn't deal with error handling yet.
2525+ let team_1_name = split_iterator.next().unwrap();
2626+ let team_2_name = split_iterator.next().unwrap();
2727+ let team_1_score: u8 = split_iterator.next().unwrap().parse().unwrap();
2828+ let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
2929+3030+ // Insert the default with zeros if a team doesn't exist yet.
3131+ let team_1 = scores.entry(team_1_name).or_default();
3232+ // Update the values.
3333+ team_1.goals_scored += team_1_score;
3434+ team_1.goals_conceded += team_2_score;
3535+3636+ // Similarly for the second team.
3737+ let team_2 = scores.entry(team_2_name).or_default();
3838+ team_2.goals_scored += team_2_score;
3939+ team_2.goals_conceded += team_1_score;
4040+ }
4141+4242+ scores
4343+}
4444+4545+fn main() {
4646+ // You can optionally experiment here.
4747+}
4848+4949+#[cfg(test)]
5050+mod tests {
5151+ use super::*;
5252+5353+ const RESULTS: &str = "England,France,4,2
5454+France,Italy,3,1
5555+Poland,Spain,2,0
5656+Germany,England,2,1
5757+England,Spain,1,0";
5858+5959+ #[test]
6060+ fn build_scores() {
6161+ let scores = build_scores_table(RESULTS);
6262+6363+ assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
6464+ .into_iter()
6565+ .all(|team_name| scores.contains_key(team_name)));
6666+ }
6767+6868+ #[test]
6969+ fn validate_team_score_1() {
7070+ let scores = build_scores_table(RESULTS);
7171+ let team = scores.get("England").unwrap();
7272+ assert_eq!(team.goals_scored, 6);
7373+ assert_eq!(team.goals_conceded, 4);
7474+ }
7575+7676+ #[test]
7777+ fn validate_team_score_2() {
7878+ let scores = build_scores_table(RESULTS);
7979+ let team = scores.get("Spain").unwrap();
8080+ assert_eq!(team.goals_scored, 0);
8181+ assert_eq!(team.goals_conceded, 3);
8282+ }
8383+}
+39
solutions/12_options/options1.rs
···11+// This function returns how much icecream there is left in the fridge.
22+// If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00,
33+// someone eats it all, so no icecream is left (value 0). Return `None` if
44+// `hour_of_day` is higher than 23.
55+fn maybe_icecream(hour_of_day: u16) -> Option<u16> {
66+ match hour_of_day {
77+ 0..=21 => Some(5),
88+ 22..=23 => Some(0),
99+ _ => None,
1010+ }
1111+}
1212+1313+fn main() {
1414+ // You can optionally experiment here.
1515+}
1616+1717+#[cfg(test)]
1818+mod tests {
1919+ use super::*;
2020+2121+ #[test]
2222+ fn raw_value() {
2323+ // Using `unwrap` is fine in a test.
2424+ let icecreams = maybe_icecream(12).unwrap();
2525+2626+ assert_eq!(icecreams, 5);
2727+ }
2828+2929+ #[test]
3030+ fn check_icecream() {
3131+ assert_eq!(maybe_icecream(0), Some(5));
3232+ assert_eq!(maybe_icecream(9), Some(5));
3333+ assert_eq!(maybe_icecream(18), Some(5));
3434+ assert_eq!(maybe_icecream(22), Some(0));
3535+ assert_eq!(maybe_icecream(23), Some(0));
3636+ assert_eq!(maybe_icecream(24), None);
3737+ assert_eq!(maybe_icecream(25), None);
3838+ }
3939+}
+37
solutions/12_options/options2.rs
···11+fn main() {
22+ // You can optionally experiment here.
33+}
44+55+#[cfg(test)]
66+mod tests {
77+ #[test]
88+ fn simple_option() {
99+ let target = "rustlings";
1010+ let optional_target = Some(target);
1111+1212+ // if-let
1313+ if let Some(word) = optional_target {
1414+ assert_eq!(word, target);
1515+ }
1616+ }
1717+1818+ #[test]
1919+ fn layered_option() {
2020+ let range = 10;
2121+ let mut optional_integers: Vec<Option<i8>> = vec![None];
2222+2323+ for i in 1..=range {
2424+ optional_integers.push(Some(i));
2525+ }
2626+2727+ let mut cursor = range;
2828+2929+ // while-let with nested pattern matching
3030+ while let Some(Some(integer)) = optional_integers.pop() {
3131+ assert_eq!(integer, cursor);
3232+ cursor -= 1;
3333+ }
3434+3535+ assert_eq!(cursor, 0);
3636+ }
3737+}
+26
solutions/12_options/options3.rs
···11+#[derive(Debug)]
22+struct Point {
33+ x: i32,
44+ y: i32,
55+}
66+77+fn main() {
88+ let optional_point = Some(Point { x: 100, y: 200 });
99+1010+ // Solution 1: Matching over the `Option` (not `&Option`) but without moving
1111+ // out of the `Some` variant.
1212+ match optional_point {
1313+ Some(ref p) => println!("Co-ordinates are {},{}", p.x, p.y),
1414+ // ^^^ added
1515+ _ => panic!("No match!"),
1616+ }
1717+1818+ // Solution 2: Matching over a reference (`&Option`) by added `&` before
1919+ // `optional_point`.
2020+ match &optional_point {
2121+ Some(p) => println!("Co-ordinates are {},{}", p.x, p.y),
2222+ _ => panic!("No match!"),
2323+ }
2424+2525+ println!("{optional_point:?}");
2626+}
+37
solutions/13_error_handling/errors1.rs
···11+fn generate_nametag_text(name: String) -> Result<String, String> {
22+ // ^^^^^^ ^^^^^^
33+ if name.is_empty() {
44+ // `Err(String)` instead of `None`.
55+ Err("Empty names aren't allowed".to_string())
66+ } else {
77+ // `Ok` instead of `Some`.
88+ Ok(format!("Hi! My name is {name}"))
99+ }
1010+}
1111+1212+fn main() {
1313+ // You can optionally experiment here.
1414+}
1515+1616+#[cfg(test)]
1717+mod tests {
1818+ use super::*;
1919+2020+ #[test]
2121+ fn generates_nametag_text_for_a_nonempty_name() {
2222+ assert_eq!(
2323+ generate_nametag_text("Beyoncé".to_string()).as_deref(),
2424+ Ok("Hi! My name is Beyoncé"),
2525+ );
2626+ }
2727+2828+ #[test]
2929+ fn explains_why_generating_nametag_text_fails() {
3030+ assert_eq!(
3131+ generate_nametag_text(String::new())
3232+ .as_ref()
3333+ .map_err(|e| e.as_str()),
3434+ Err("Empty names aren't allowed"),
3535+ );
3636+ }
3737+}
+58
solutions/13_error_handling/errors2.rs
···11+// Say we're writing a game where you can buy items with tokens. All items cost
22+// 5 tokens, and whenever you purchase items there is a processing fee of 1
33+// token. A player of the game will type in how many items they want to buy, and
44+// the `total_cost` function will calculate the total cost of the items. Since
55+// the player typed in the quantity, we get it as a string. They might have
66+// typed anything, not just numbers!
77+//
88+// Right now, this function isn't handling the error case at all. What we want
99+// to do is: If we call the `total_cost` function on a string that is not a
1010+// number, that function will return a `ParseIntError`. In that case, we want to
1111+// immediately return that error from our function and not try to multiply and
1212+// add.
1313+//
1414+// There are at least two ways to implement this that are both correct. But one
1515+// is a lot shorter!
1616+1717+use std::num::ParseIntError;
1818+1919+#[allow(unused_variables)]
2020+fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
2121+ let processing_fee = 1;
2222+ let cost_per_item = 5;
2323+2424+ // Added `?` to propagate the error.
2525+ let qty = item_quantity.parse::<i32>()?;
2626+ // ^ added
2727+2828+ // Equivalent to this verbose version:
2929+ let qty = match item_quantity.parse::<i32>() {
3030+ Ok(v) => v,
3131+ Err(e) => return Err(e),
3232+ };
3333+3434+ Ok(qty * cost_per_item + processing_fee)
3535+}
3636+3737+fn main() {
3838+ // You can optionally experiment here.
3939+}
4040+4141+#[cfg(test)]
4242+mod tests {
4343+ use super::*;
4444+ use std::num::IntErrorKind;
4545+4646+ #[test]
4747+ fn item_quantity_is_a_valid_number() {
4848+ assert_eq!(total_cost("34"), Ok(171));
4949+ }
5050+5151+ #[test]
5252+ fn item_quantity_is_an_invalid_number() {
5353+ assert_eq!(
5454+ total_cost("beep boop").unwrap_err().kind(),
5555+ &IntErrorKind::InvalidDigit,
5656+ );
5757+ }
5858+}
+32
solutions/13_error_handling/errors3.rs
···11+// This is a program that is trying to use a completed version of the
22+// `total_cost` function from the previous exercise. It's not working though!
33+// Why not? What should we do to fix it?
44+55+use std::num::ParseIntError;
66+77+// Don't change this function.
88+fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
99+ let processing_fee = 1;
1010+ let cost_per_item = 5;
1111+ let qty = item_quantity.parse::<i32>()?;
1212+1313+ Ok(qty * cost_per_item + processing_fee)
1414+}
1515+1616+fn main() -> Result<(), ParseIntError> {
1717+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ added
1818+ let mut tokens = 100;
1919+ let pretend_user_input = "8";
2020+2121+ let cost = total_cost(pretend_user_input)?;
2222+2323+ if cost > tokens {
2424+ println!("You can't afford that many!");
2525+ } else {
2626+ tokens -= cost;
2727+ println!("You now have {tokens} tokens.");
2828+ }
2929+3030+ // Added this line to return the `Ok` variant of the expected `Result`.
3131+ Ok(())
3232+}
···11+// This exercise is an altered version of the `errors4` exercise. It uses some
22+// concepts that we won't get to until later in the course, like `Box` and the
33+// `From` trait. It's not important to understand them in detail right now, but
44+// you can read ahead if you like. For now, think of the `Box<dyn ???>` type as
55+// an "I want anything that does ???" type.
66+//
77+// In short, this particular use case for boxes is for when you want to own a
88+// value and you care only that it is a type which implements a particular
99+// trait. To do so, The `Box` is declared as of type `Box<dyn Trait>` where
1010+// `Trait` is the trait the compiler looks for on any value used in that
1111+// context. For this exercise, that context is the potential errors which
1212+// can be returned in a `Result`.
1313+1414+use std::error::Error;
1515+use std::fmt;
1616+1717+#[derive(PartialEq, Debug)]
1818+enum CreationError {
1919+ Negative,
2020+ Zero,
2121+}
2222+2323+// This is required so that `CreationError` can implement `Error`.
2424+impl fmt::Display for CreationError {
2525+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2626+ let description = match *self {
2727+ CreationError::Negative => "number is negative",
2828+ CreationError::Zero => "number is zero",
2929+ };
3030+ f.write_str(description)
3131+ }
3232+}
3333+3434+impl Error for CreationError {}
3535+3636+#[derive(PartialEq, Debug)]
3737+struct PositiveNonzeroInteger(u64);
3838+3939+impl PositiveNonzeroInteger {
4040+ fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
4141+ match value {
4242+ x if x < 0 => Err(CreationError::Negative),
4343+ 0 => Err(CreationError::Zero),
4444+ x => Ok(PositiveNonzeroInteger(x as u64)),
4545+ }
4646+ }
4747+}
4848+4949+fn main() -> Result<(), Box<dyn Error>> {
5050+ let pretend_user_input = "42";
5151+ let x: i64 = pretend_user_input.parse()?;
5252+ println!("output={:?}", PositiveNonzeroInteger::new(x)?);
5353+ Ok(())
5454+}
+91
solutions/13_error_handling/errors6.rs
···11+// Using catch-all error types like `Box<dyn Error>` isn't recommended for
22+// library code where callers might want to make decisions based on the error
33+// content instead of printing it out or propagating it further. Here, we define
44+// a custom error type to make it possible for callers to decide what to do next
55+// when our function returns an error.
66+77+use std::num::ParseIntError;
88+99+#[derive(PartialEq, Debug)]
1010+enum CreationError {
1111+ Negative,
1212+ Zero,
1313+}
1414+1515+// A custom error type that we will be using in `PositiveNonzeroInteger::parse`.
1616+#[derive(PartialEq, Debug)]
1717+enum ParsePosNonzeroError {
1818+ Creation(CreationError),
1919+ ParseInt(ParseIntError),
2020+}
2121+2222+impl ParsePosNonzeroError {
2323+ fn from_creation(err: CreationError) -> Self {
2424+ Self::Creation(err)
2525+ }
2626+2727+ fn from_parse_int(err: ParseIntError) -> Self {
2828+ Self::ParseInt(err)
2929+ }
3030+}
3131+3232+#[derive(PartialEq, Debug)]
3333+struct PositiveNonzeroInteger(u64);
3434+3535+impl PositiveNonzeroInteger {
3636+ fn new(value: i64) -> Result<Self, CreationError> {
3737+ match value {
3838+ x if x < 0 => Err(CreationError::Negative),
3939+ 0 => Err(CreationError::Zero),
4040+ x => Ok(Self(x as u64)),
4141+ }
4242+ }
4343+4444+ fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
4545+ // Return an appropriate error instead of panicking when `parse()`
4646+ // returns an error.
4747+ let x: i64 = s.parse().map_err(ParsePosNonzeroError::from_parse_int)?;
4848+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4949+ Self::new(x).map_err(ParsePosNonzeroError::from_creation)
5050+ }
5151+}
5252+5353+fn main() {
5454+ // You can optionally experiment here.
5555+}
5656+5757+#[cfg(test)]
5858+mod test {
5959+ use super::*;
6060+6161+ #[test]
6262+ fn test_parse_error() {
6363+ assert!(matches!(
6464+ PositiveNonzeroInteger::parse("not a number"),
6565+ Err(ParsePosNonzeroError::ParseInt(_)),
6666+ ));
6767+ }
6868+6969+ #[test]
7070+ fn test_negative() {
7171+ assert_eq!(
7272+ PositiveNonzeroInteger::parse("-555"),
7373+ Err(ParsePosNonzeroError::Creation(CreationError::Negative)),
7474+ );
7575+ }
7676+7777+ #[test]
7878+ fn test_zero() {
7979+ assert_eq!(
8080+ PositiveNonzeroInteger::parse("0"),
8181+ Err(ParsePosNonzeroError::Creation(CreationError::Zero)),
8282+ );
8383+ }
8484+8585+ #[test]
8686+ fn test_positive() {
8787+ let x = PositiveNonzeroInteger::new(42).unwrap();
8888+ assert_eq!(x.0, 42);
8989+ assert_eq!(PositiveNonzeroInteger::parse("42"), Ok(x));
9090+ }
9191+}
+17
solutions/14_generics/generics1.rs
···11+// `Vec<T>` is generic over the type `T`. In most cases, the compiler is able to
22+// infer `T`, for example after pushing a value with a concrete type to the vector.
33+// But in this exercise, the compiler needs some help through a type annotation.
44+55+fn main() {
66+ // `u8` and `i8` can both be converted to `i16`.
77+ let mut numbers: Vec<i16> = Vec::new();
88+ // ^^^^^^^^^^ added
99+1010+ // Don't change the lines below.
1111+ let n1: u8 = 42;
1212+ numbers.push(n1.into());
1313+ let n2: i8 = -1;
1414+ numbers.push(n2.into());
1515+1616+ println!("{numbers:?}");
1717+}
···11+// The Rust compiler needs to know how to check whether supplied references are
22+// valid, so that it can let the programmer know if a reference is at risk of
33+// going out of scope before it is used. Remember, references are borrows and do
44+// not own their own data. What if their owner goes out of scope?
55+66+fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
77+ // ^^^^ ^^ ^^ ^^
88+ if x.len() > y.len() {
99+ x
1010+ } else {
1111+ y
1212+ }
1313+}
1414+1515+fn main() {
1616+ // You can optionally experiment here.
1717+}
1818+1919+#[cfg(test)]
2020+mod tests {
2121+ use super::*;
2222+2323+ #[test]
2424+ fn test_longest() {
2525+ assert_eq!(longest("abcd", "123"), "abcd");
2626+ assert_eq!(longest("abc", "1234"), "1234");
2727+ }
2828+}
+33
solutions/16_lifetimes/lifetimes2.rs
···11+fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
22+ if x.len() > y.len() {
33+ x
44+ } else {
55+ y
66+ }
77+}
88+99+fn main() {
1010+ let string1 = String::from("long string is long");
1111+ // Solution1: You can move `strings2` out of the inner block so that it is
1212+ // not dropped before the print statement.
1313+ let string2 = String::from("xyz");
1414+ let result;
1515+ {
1616+ result = longest(&string1, &string2);
1717+ }
1818+ println!("The longest string is '{result}'");
1919+ // `string2` dropped at the end of the function.
2020+2121+ // =========================================================================
2222+2323+ let string1 = String::from("long string is long");
2424+ let result;
2525+ {
2626+ let string2 = String::from("xyz");
2727+ result = longest(&string1, &string2);
2828+ // Solution2: You can move the print statement into the inner block so
2929+ // that it is executed before `string2` is dropped.
3030+ println!("The longest string is '{result}'");
3131+ // `string2` dropped here (end of the inner scope).
3232+ }
3333+}
+18
solutions/16_lifetimes/lifetimes3.rs
···11+// Lifetimes are also needed when structs hold references.
22+33+struct Book<'a> {
44+ // ^^^^ added a lifetime annotation
55+ author: &'a str,
66+ // ^^
77+ title: &'a str,
88+ // ^^
99+}
1010+1111+fn main() {
1212+ let book = Book {
1313+ author: "George Orwell",
1414+ title: "1984",
1515+ };
1616+1717+ println!("{} by {}", book.title, book.author);
1818+}
+24
solutions/17_tests/tests1.rs
···11+// Tests are important to ensure that your code does what you think it should
22+// do.
33+44+fn is_even(n: i64) -> bool {
55+ n % 2 == 0
66+}
77+88+fn main() {
99+ // You can optionally experiment here.
1010+}
1111+1212+#[cfg(test)]
1313+mod tests {
1414+ // When writing unit tests, it is common to import everything from the outer
1515+ // module (`super`) using a wildcard.
1616+ use super::*;
1717+1818+ #[test]
1919+ fn you_can_assert() {
2020+ assert!(is_even(0));
2121+ assert!(!is_even(-1));
2222+ // ^ You can assert `false` using the negation operator `!`.
2323+ }
2424+}
+22
solutions/17_tests/tests2.rs
···11+// Calculates the power of 2 using a bit shift.
22+// `1 << n` is equivalent to "2 to the power of n".
33+fn power_of_2(n: u8) -> u64 {
44+ 1 << n
55+}
66+77+fn main() {
88+ // You can optionally experiment here.
99+}
1010+1111+#[cfg(test)]
1212+mod tests {
1313+ use super::*;
1414+1515+ #[test]
1616+ fn you_can_assert_eq() {
1717+ assert_eq!(power_of_2(0), 1);
1818+ assert_eq!(power_of_2(1), 2);
1919+ assert_eq!(power_of_2(2), 4);
2020+ assert_eq!(power_of_2(3), 8);
2121+ }
2222+}
+45
solutions/17_tests/tests3.rs
···11+struct Rectangle {
22+ width: i32,
33+ height: i32,
44+}
55+66+impl Rectangle {
77+ // Don't change this function.
88+ fn new(width: i32, height: i32) -> Self {
99+ if width <= 0 || height <= 0 {
1010+ // Returning a `Result` would be better here. But we want to learn
1111+ // how to test functions that can panic.
1212+ panic!("Rectangle width and height must be positive");
1313+ }
1414+1515+ Rectangle { width, height }
1616+ }
1717+}
1818+1919+fn main() {
2020+ // You can optionally experiment here.
2121+}
2222+2323+#[cfg(test)]
2424+mod tests {
2525+ use super::*;
2626+2727+ #[test]
2828+ fn correct_width_and_height() {
2929+ let rect = Rectangle::new(10, 20);
3030+ assert_eq!(rect.width, 10); // Check width
3131+ assert_eq!(rect.height, 20); // Check height
3232+ }
3333+3434+ #[test]
3535+ #[should_panic] // Added this attribute to check that the test panics.
3636+ fn negative_width() {
3737+ let _rect = Rectangle::new(-10, 10);
3838+ }
3939+4040+ #[test]
4141+ #[should_panic] // Added this attribute to check that the test panics.
4242+ fn negative_height() {
4343+ let _rect = Rectangle::new(10, -10);
4444+ }
4545+}
+26
solutions/18_iterators/iterators1.rs
···11+// When performing operations on elements within a collection, iterators are
22+// essential. This module helps you get familiar with the structure of using an
33+// iterator and how to go through elements within an iterable collection.
44+55+fn main() {
66+ // You can optionally experiment here.
77+}
88+99+#[cfg(test)]
1010+mod tests {
1111+ #[test]
1212+ fn iterators() {
1313+ let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"];
1414+1515+ // Create an iterator over the array.
1616+ let mut fav_fruits_iterator = my_fav_fruits.iter();
1717+1818+ assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
1919+ assert_eq!(fav_fruits_iterator.next(), Some(&"custard apple"));
2020+ assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
2121+ assert_eq!(fav_fruits_iterator.next(), Some(&"peach"));
2222+ assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
2323+ assert_eq!(fav_fruits_iterator.next(), None);
2424+ // ^^^^ reached the end
2525+ }
2626+}
+56
solutions/18_iterators/iterators2.rs
···11+// In this exercise, you'll learn some of the unique advantages that iterators
22+// can offer.
33+44+// "hello" -> "Hello"
55+fn capitalize_first(input: &str) -> String {
66+ let mut chars = input.chars();
77+ match chars.next() {
88+ None => String::new(),
99+ Some(first) => first.to_uppercase().to_string() + chars.as_str(),
1010+ }
1111+}
1212+1313+// Apply the `capitalize_first` function to a slice of string slices.
1414+// Return a vector of strings.
1515+// ["hello", "world"] -> ["Hello", "World"]
1616+fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
1717+ words.iter().map(|word| capitalize_first(word)).collect()
1818+}
1919+2020+// Apply the `capitalize_first` function again to a slice of string
2121+// slices. Return a single string.
2222+// ["hello", " ", "world"] -> "Hello World"
2323+fn capitalize_words_string(words: &[&str]) -> String {
2424+ words.iter().map(|word| capitalize_first(word)).collect()
2525+}
2626+2727+fn main() {
2828+ // You can optionally experiment here.
2929+}
3030+3131+#[cfg(test)]
3232+mod tests {
3333+ use super::*;
3434+3535+ #[test]
3636+ fn test_success() {
3737+ assert_eq!(capitalize_first("hello"), "Hello");
3838+ }
3939+4040+ #[test]
4141+ fn test_empty() {
4242+ assert_eq!(capitalize_first(""), "");
4343+ }
4444+4545+ #[test]
4646+ fn test_iterate_string_vec() {
4747+ let words = vec!["hello", "world"];
4848+ assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
4949+ }
5050+5151+ #[test]
5252+ fn test_iterate_into_string() {
5353+ let words = vec!["hello", " ", "world"];
5454+ assert_eq!(capitalize_words_string(&words), "Hello World");
5555+ }
5656+}
+86
solutions/18_iterators/iterators3.rs
···11+#[derive(Debug, PartialEq, Eq)]
22+enum DivisionError {
33+ // Example: 42 / 0
44+ DivideByZero,
55+ // Only case for `i64`: `i64::MIN / -1` because the result is `i64::MAX + 1`
66+ IntegerOverflow,
77+ // Example: 5 / 2 = 2.5
88+ NotDivisible,
99+}
1010+1111+fn divide(a: i64, b: i64) -> Result<i64, DivisionError> {
1212+ if b == 0 {
1313+ return Err(DivisionError::DivideByZero);
1414+ }
1515+1616+ if a == i64::MIN && b == -1 {
1717+ return Err(DivisionError::IntegerOverflow);
1818+ }
1919+2020+ if a % b != 0 {
2121+ return Err(DivisionError::NotDivisible);
2222+ }
2323+2424+ Ok(a / b)
2525+}
2626+2727+fn result_with_list() -> Result<Vec<i64>, DivisionError> {
2828+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2929+ let numbers = [27, 297, 38502, 81];
3030+ let division_results = numbers.into_iter().map(|n| divide(n, 27));
3131+ // Collects to the expected return type. Returns the first error in the
3232+ // division results (if one exists).
3333+ division_results.collect()
3434+}
3535+3636+fn list_of_results() -> Vec<Result<i64, DivisionError>> {
3737+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838+ let numbers = [27, 297, 38502, 81];
3939+ let division_results = numbers.into_iter().map(|n| divide(n, 27));
4040+ // Collects to the expected return type.
4141+ division_results.collect()
4242+}
4343+4444+fn main() {
4545+ // You can optionally experiment here.
4646+}
4747+4848+#[cfg(test)]
4949+mod tests {
5050+ use super::*;
5151+5252+ #[test]
5353+ fn test_success() {
5454+ assert_eq!(divide(81, 9), Ok(9));
5555+ }
5656+5757+ #[test]
5858+ fn test_divide_by_0() {
5959+ assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
6060+ }
6161+6262+ #[test]
6363+ fn test_integer_overflow() {
6464+ assert_eq!(divide(i64::MIN, -1), Err(DivisionError::IntegerOverflow));
6565+ }
6666+6767+ #[test]
6868+ fn test_not_divisible() {
6969+ assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));
7070+ }
7171+7272+ #[test]
7373+ fn test_divide_0_by_something() {
7474+ assert_eq!(divide(0, 81), Ok(0));
7575+ }
7676+7777+ #[test]
7878+ fn test_result_with_list() {
7979+ assert_eq!(result_with_list().unwrap(), [1, 11, 1426, 3]);
8080+ }
8181+8282+ #[test]
8383+ fn test_list_of_results() {
8484+ assert_eq!(list_of_results(), [Ok(1), Ok(11), Ok(1426), Ok(3)]);
8585+ }
8686+}
+72
solutions/18_iterators/iterators4.rs
···11+// 3 possible solutions are presented.
22+33+// With `for` loop and a mutable variable.
44+fn factorial_for(num: u64) -> u64 {
55+ let mut result = 1;
66+77+ for x in 2..=num {
88+ result *= x;
99+ }
1010+1111+ result
1212+}
1313+1414+// Equivalent to `factorial_for` but shorter and without a `for` loop and
1515+// mutable variables.
1616+fn factorial_fold(num: u64) -> u64 {
1717+ // Case num==0: The iterator 2..=0 is empty
1818+ // -> The initial value of `fold` is returned which is 1.
1919+ // Case num==1: The iterator 2..=1 is also empty
2020+ // -> The initial value 1 is returned.
2121+ // Case num==2: The iterator 2..=2 contains one element
2222+ // -> The initial value 1 is multiplied by 2 and the result
2323+ // is returned.
2424+ // Case num==3: The iterator 2..=3 contains 2 elements
2525+ // -> 1 * 2 is calculated, then the result 2 is multiplied by
2626+ // the second element 3 so the result 6 is returned.
2727+ // And so on…
2828+ #[allow(clippy::unnecessary_fold)]
2929+ (2..=num).fold(1, |acc, x| acc * x)
3030+}
3131+3232+// Equivalent to `factorial_fold` but with a built-in method that is suggested
3333+// by Clippy.
3434+fn factorial_product(num: u64) -> u64 {
3535+ (2..=num).product()
3636+}
3737+3838+fn main() {
3939+ // You can optionally experiment here.
4040+}
4141+4242+#[cfg(test)]
4343+mod tests {
4444+ use super::*;
4545+4646+ #[test]
4747+ fn factorial_of_0() {
4848+ assert_eq!(factorial_for(0), 1);
4949+ assert_eq!(factorial_fold(0), 1);
5050+ assert_eq!(factorial_product(0), 1);
5151+ }
5252+5353+ #[test]
5454+ fn factorial_of_1() {
5555+ assert_eq!(factorial_for(1), 1);
5656+ assert_eq!(factorial_fold(1), 1);
5757+ assert_eq!(factorial_product(1), 1);
5858+ }
5959+ #[test]
6060+ fn factorial_of_2() {
6161+ assert_eq!(factorial_for(2), 2);
6262+ assert_eq!(factorial_fold(2), 2);
6363+ assert_eq!(factorial_product(2), 2);
6464+ }
6565+6666+ #[test]
6767+ fn factorial_of_4() {
6868+ assert_eq!(factorial_for(4), 24);
6969+ assert_eq!(factorial_fold(4), 24);
7070+ assert_eq!(factorial_product(4), 24);
7171+ }
7272+}
+168
solutions/18_iterators/iterators5.rs
···11+// Let's define a simple model to track Rustlings' exercise progress. Progress
22+// will be modelled using a hash map. The name of the exercise is the key and
33+// the progress is the value. Two counting functions were created to count the
44+// number of exercises with a given progress. Recreate this counting
55+// functionality using iterators. Try to not use imperative loops (for/while).
66+77+use std::collections::HashMap;
88+99+#[derive(Clone, Copy, PartialEq, Eq)]
1010+enum Progress {
1111+ None,
1212+ Some,
1313+ Complete,
1414+}
1515+1616+fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
1717+ let mut count = 0;
1818+ for val in map.values() {
1919+ if *val == value {
2020+ count += 1;
2121+ }
2222+ }
2323+ count
2424+}
2525+2626+fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
2727+ // `map` is a hash map with `String` keys and `Progress` values.
2828+ // map = { "variables1": Complete, "from_str": None, … }
2929+ map.values().filter(|val| **val == value).count()
3030+}
3131+3232+fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
3333+ let mut count = 0;
3434+ for map in collection {
3535+ count += count_for(map, value);
3636+ }
3737+ count
3838+}
3939+4040+fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
4141+ // `collection` is a slice of hash maps.
4242+ // collection = [{ "variables1": Complete, "from_str": None, … },
4343+ // { "variables2": Complete, … }, … ]
4444+ collection
4545+ .iter()
4646+ .map(|map| count_iterator(map, value))
4747+ .sum()
4848+}
4949+5050+// Equivalent to `count_collection_iterator` and `count_iterator`, iterating as
5151+// if the collection was a single container instead of a container of containers
5252+// (and more accurately, a single iterator instead of an iterator of iterators).
5353+fn count_collection_iterator_flat(
5454+ collection: &[HashMap<String, Progress>],
5555+ value: Progress,
5656+) -> usize {
5757+ // `collection` is a slice of hash maps.
5858+ // collection = [{ "variables1": Complete, "from_str": None, … },
5959+ // { "variables2": Complete, … }, … ]
6060+ collection
6161+ .iter()
6262+ .flat_map(HashMap::values) // or just `.flatten()` when wanting the default iterator (`HashMap::iter`)
6363+ .filter(|val| **val == value)
6464+ .count()
6565+}
6666+6767+fn main() {
6868+ // You can optionally experiment here.
6969+}
7070+7171+#[cfg(test)]
7272+mod tests {
7373+ use super::*;
7474+ use Progress::*;
7575+7676+ fn get_map() -> HashMap<String, Progress> {
7777+ let mut map = HashMap::new();
7878+ map.insert(String::from("variables1"), Complete);
7979+ map.insert(String::from("functions1"), Complete);
8080+ map.insert(String::from("hashmap1"), Complete);
8181+ map.insert(String::from("arc1"), Some);
8282+ map.insert(String::from("as_ref_mut"), None);
8383+ map.insert(String::from("from_str"), None);
8484+8585+ map
8686+ }
8787+8888+ fn get_vec_map() -> Vec<HashMap<String, Progress>> {
8989+ let map = get_map();
9090+9191+ let mut other = HashMap::new();
9292+ other.insert(String::from("variables2"), Complete);
9393+ other.insert(String::from("functions2"), Complete);
9494+ other.insert(String::from("if1"), Complete);
9595+ other.insert(String::from("from_into"), None);
9696+ other.insert(String::from("try_from_into"), None);
9797+9898+ vec![map, other]
9999+ }
100100+101101+ #[test]
102102+ fn count_complete() {
103103+ let map = get_map();
104104+ assert_eq!(count_iterator(&map, Complete), 3);
105105+ }
106106+107107+ #[test]
108108+ fn count_some() {
109109+ let map = get_map();
110110+ assert_eq!(count_iterator(&map, Some), 1);
111111+ }
112112+113113+ #[test]
114114+ fn count_none() {
115115+ let map = get_map();
116116+ assert_eq!(count_iterator(&map, None), 2);
117117+ }
118118+119119+ #[test]
120120+ fn count_complete_equals_for() {
121121+ let map = get_map();
122122+ let progress_states = [Complete, Some, None];
123123+ for progress_state in progress_states {
124124+ assert_eq!(
125125+ count_for(&map, progress_state),
126126+ count_iterator(&map, progress_state),
127127+ );
128128+ }
129129+ }
130130+131131+ #[test]
132132+ fn count_collection_complete() {
133133+ let collection = get_vec_map();
134134+ assert_eq!(count_collection_iterator(&collection, Complete), 6);
135135+ assert_eq!(count_collection_iterator_flat(&collection, Complete), 6);
136136+ }
137137+138138+ #[test]
139139+ fn count_collection_some() {
140140+ let collection = get_vec_map();
141141+ assert_eq!(count_collection_iterator(&collection, Some), 1);
142142+ assert_eq!(count_collection_iterator_flat(&collection, Some), 1);
143143+ }
144144+145145+ #[test]
146146+ fn count_collection_none() {
147147+ let collection = get_vec_map();
148148+ assert_eq!(count_collection_iterator(&collection, None), 4);
149149+ assert_eq!(count_collection_iterator_flat(&collection, None), 4);
150150+ }
151151+152152+ #[test]
153153+ fn count_collection_equals_for() {
154154+ let collection = get_vec_map();
155155+ let progress_states = [Complete, Some, None];
156156+157157+ for progress_state in progress_states {
158158+ assert_eq!(
159159+ count_collection_for(&collection, progress_state),
160160+ count_collection_iterator(&collection, progress_state),
161161+ );
162162+ assert_eq!(
163163+ count_collection_for(&collection, progress_state),
164164+ count_collection_iterator_flat(&collection, progress_state),
165165+ );
166166+ }
167167+ }
168168+}
+45
solutions/19_smart_pointers/arc1.rs
···11+// In this exercise, we are given a `Vec` of `u32` called `numbers` with values
22+// ranging from 0 to 99. We would like to use this set of numbers within 8
33+// different threads simultaneously. Each thread is going to get the sum of
44+// every eighth value with an offset.
55+//
66+// The first thread (offset 0), will sum 0, 8, 16, …
77+// The second thread (offset 1), will sum 1, 9, 17, …
88+// The third thread (offset 2), will sum 2, 10, 18, …
99+// …
1010+// The eighth thread (offset 7), will sum 7, 15, 23, …
1111+//
1212+// Each thread should own a reference-counting pointer to the vector of
1313+// numbers. But `Rc` isn't thread-safe. Therefore, we need to use `Arc`.
1414+//
1515+// Don't get distracted by how threads are spawned and joined. We will practice
1616+// that later in the exercises about threads.
1717+1818+// Don't change the lines below.
1919+#![forbid(unused_imports)]
2020+use std::{sync::Arc, thread};
2121+2222+fn main() {
2323+ let numbers: Vec<_> = (0..100u32).collect();
2424+2525+ let shared_numbers = Arc::new(numbers);
2626+ // ^^^^^^^^^^^^^^^^^
2727+2828+ let mut join_handles = Vec::new();
2929+3030+ for offset in 0..8 {
3131+ let child_numbers = Arc::clone(&shared_numbers);
3232+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3333+3434+ let handle = thread::spawn(move || {
3535+ let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
3636+ println!("Sum of offset {offset} is {sum}");
3737+ });
3838+3939+ join_handles.push(handle);
4040+ }
4141+4242+ for handle in join_handles.into_iter() {
4343+ handle.join().unwrap();
4444+ }
4545+}
+47
solutions/19_smart_pointers/box1.rs
···11+// At compile time, Rust needs to know how much space a type takes up. This
22+// becomes problematic for recursive types, where a value can have as part of
33+// itself another value of the same type. To get around the issue, we can use a
44+// `Box` - a smart pointer used to store data on the heap, which also allows us
55+// to wrap a recursive type.
66+//
77+// The recursive type we're implementing in this exercise is the "cons list", a
88+// data structure frequently found in functional programming languages. Each
99+// item in a cons list contains two elements: The value of the current item and
1010+// the next item. The last item is a value called `Nil`.
1111+1212+#[derive(PartialEq, Debug)]
1313+enum List {
1414+ Cons(i32, Box<List>),
1515+ Nil,
1616+}
1717+1818+fn create_empty_list() -> List {
1919+ List::Nil
2020+}
2121+2222+fn create_non_empty_list() -> List {
2323+ List::Cons(42, Box::new(List::Nil))
2424+}
2525+2626+fn main() {
2727+ println!("This is an empty cons list: {:?}", create_empty_list());
2828+ println!(
2929+ "This is a non-empty cons list: {:?}",
3030+ create_non_empty_list(),
3131+ );
3232+}
3333+3434+#[cfg(test)]
3535+mod tests {
3636+ use super::*;
3737+3838+ #[test]
3939+ fn test_create_empty_list() {
4040+ assert_eq!(create_empty_list(), List::Nil);
4141+ }
4242+4343+ #[test]
4444+ fn test_create_non_empty_list() {
4545+ assert_ne!(create_empty_list(), create_non_empty_list());
4646+ }
4747+}
+69
solutions/19_smart_pointers/cow1.rs
···11+// This exercise explores the `Cow` (Clone-On-Write) smart pointer. It can
22+// enclose and provide immutable access to borrowed data and clone the data
33+// lazily when mutation or ownership is required. The type is designed to work
44+// with general borrowed data via the `Borrow` trait.
55+66+use std::borrow::Cow;
77+88+fn abs_all(input: &mut Cow<[i32]>) {
99+ for ind in 0..input.len() {
1010+ let value = input[ind];
1111+ if value < 0 {
1212+ // Clones into a vector if not already owned.
1313+ input.to_mut()[ind] = -value;
1414+ }
1515+ }
1616+}
1717+1818+fn main() {
1919+ // You can optionally experiment here.
2020+}
2121+2222+#[cfg(test)]
2323+mod tests {
2424+ use super::*;
2525+2626+ #[test]
2727+ fn reference_mutation() {
2828+ // Clone occurs because `input` needs to be mutated.
2929+ let vec = vec![-1, 0, 1];
3030+ let mut input = Cow::from(&vec);
3131+ abs_all(&mut input);
3232+ assert!(matches!(input, Cow::Owned(_)));
3333+ }
3434+3535+ #[test]
3636+ fn reference_no_mutation() {
3737+ // No clone occurs because `input` doesn't need to be mutated.
3838+ let vec = vec![0, 1, 2];
3939+ let mut input = Cow::from(&vec);
4040+ abs_all(&mut input);
4141+ assert!(matches!(input, Cow::Borrowed(_)));
4242+ // ^^^^^^^^^^^^^^^^
4343+ }
4444+4545+ #[test]
4646+ fn owned_no_mutation() {
4747+ // We can also pass `vec` without `&` so `Cow` owns it directly. In this
4848+ // case, no mutation occurs (all numbers are already absolute) and thus
4949+ // also no clone. But the result is still owned because it was never
5050+ // borrowed or mutated.
5151+ let vec = vec![0, 1, 2];
5252+ let mut input = Cow::from(vec);
5353+ abs_all(&mut input);
5454+ assert!(matches!(input, Cow::Owned(_)));
5555+ // ^^^^^^^^^^^^^
5656+ }
5757+5858+ #[test]
5959+ fn owned_mutation() {
6060+ // Of course this is also the case if a mutation does occur (not all
6161+ // numbers are absolute). In this case, the call to `to_mut()` in the
6262+ // `abs_all` function returns a reference to the same data as before.
6363+ let vec = vec![-1, 0, 1];
6464+ let mut input = Cow::from(vec);
6565+ abs_all(&mut input);
6666+ assert!(matches!(input, Cow::Owned(_)));
6767+ // ^^^^^^^^^^^^^
6868+ }
6969+}
+104
solutions/19_smart_pointers/rc1.rs
···11+// In this exercise, we want to express the concept of multiple owners via the
22+// `Rc<T>` type. This is a model of our solar system - there is a `Sun` type and
33+// multiple `Planet`s. The planets take ownership of the sun, indicating that
44+// they revolve around the sun.
55+66+use std::rc::Rc;
77+88+#[derive(Debug)]
99+struct Sun;
1010+1111+#[derive(Debug)]
1212+enum Planet {
1313+ Mercury(Rc<Sun>),
1414+ Venus(Rc<Sun>),
1515+ Earth(Rc<Sun>),
1616+ Mars(Rc<Sun>),
1717+ Jupiter(Rc<Sun>),
1818+ Saturn(Rc<Sun>),
1919+ Uranus(Rc<Sun>),
2020+ Neptune(Rc<Sun>),
2121+}
2222+2323+impl Planet {
2424+ fn details(&self) {
2525+ println!("Hi from {self:?}!");
2626+ }
2727+}
2828+2929+fn main() {
3030+ // You can optionally experiment here.
3131+}
3232+3333+#[cfg(test)]
3434+mod tests {
3535+ use super::*;
3636+3737+ #[test]
3838+ fn rc1() {
3939+ let sun = Rc::new(Sun);
4040+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
4141+4242+ let mercury = Planet::Mercury(Rc::clone(&sun));
4343+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
4444+ mercury.details();
4545+4646+ let venus = Planet::Venus(Rc::clone(&sun));
4747+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
4848+ venus.details();
4949+5050+ let earth = Planet::Earth(Rc::clone(&sun));
5151+ println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
5252+ earth.details();
5353+5454+ let mars = Planet::Mars(Rc::clone(&sun));
5555+ println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
5656+ mars.details();
5757+5858+ let jupiter = Planet::Jupiter(Rc::clone(&sun));
5959+ println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
6060+ jupiter.details();
6161+6262+ let saturn = Planet::Saturn(Rc::clone(&sun));
6363+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
6464+ saturn.details();
6565+6666+ // TODO
6767+ let uranus = Planet::Uranus(Rc::clone(&sun));
6868+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
6969+ uranus.details();
7070+7171+ // TODO
7272+ let neptune = Planet::Neptune(Rc::clone(&sun));
7373+ println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
7474+ neptune.details();
7575+7676+ assert_eq!(Rc::strong_count(&sun), 9);
7777+7878+ drop(neptune);
7979+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
8080+8181+ drop(uranus);
8282+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
8383+8484+ drop(saturn);
8585+ println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
8686+8787+ drop(jupiter);
8888+ println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
8989+9090+ drop(mars);
9191+ println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
9292+9393+ drop(earth);
9494+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
9595+9696+ drop(venus);
9797+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
9898+9999+ drop(mercury);
100100+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
101101+102102+ assert_eq!(Rc::strong_count(&sun), 1);
103103+ }
104104+}
+37
solutions/20_threads/threads1.rs
···11+// This program spawns multiple threads that each runs for at least 250ms, and
22+// each thread returns how much time it took to complete. The program should
33+// wait until all the spawned threads have finished and should collect their
44+// return values into a vector.
55+66+use std::{
77+ thread,
88+ time::{Duration, Instant},
99+};
1010+1111+fn main() {
1212+ let mut handles = Vec::new();
1313+ for i in 0..10 {
1414+ let handle = thread::spawn(move || {
1515+ let start = Instant::now();
1616+ thread::sleep(Duration::from_millis(250));
1717+ println!("Thread {i} done");
1818+ start.elapsed().as_millis()
1919+ });
2020+ handles.push(handle);
2121+ }
2222+2323+ let mut results = Vec::new();
2424+ for handle in handles {
2525+ // Collect the results of all threads into the `results` vector.
2626+ results.push(handle.join().unwrap());
2727+ }
2828+2929+ if results.len() != 10 {
3030+ panic!("Oh no! Some thread isn't done yet!");
3131+ }
3232+3333+ println!();
3434+ for (i, result) in results.into_iter().enumerate() {
3535+ println!("Thread {i} took {result}ms");
3636+ }
3737+}
+41
solutions/20_threads/threads2.rs
···11+// Building on the last exercise, we want all of the threads to complete their
22+// work. But this time, the spawned threads need to be in charge of updating a
33+// shared value: `JobStatus.jobs_done`
44+55+use std::{
66+ sync::{Arc, Mutex},
77+ thread,
88+ time::Duration,
99+};
1010+1111+struct JobStatus {
1212+ jobs_done: u32,
1313+}
1414+1515+fn main() {
1616+ // `Arc` isn't enough if you want a **mutable** shared state.
1717+ // We need to wrap the value with a `Mutex`.
1818+ let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
1919+ // ^^^^^^^^^^^ ^
2020+2121+ let mut handles = Vec::new();
2222+ for _ in 0..10 {
2323+ let status_shared = Arc::clone(&status);
2424+ let handle = thread::spawn(move || {
2525+ thread::sleep(Duration::from_millis(250));
2626+2727+ // Lock before you update a shared value.
2828+ status_shared.lock().unwrap().jobs_done += 1;
2929+ // ^^^^^^^^^^^^^^^^
3030+ });
3131+ handles.push(handle);
3232+ }
3333+3434+ // Waiting for all jobs to complete.
3535+ for handle in handles {
3636+ handle.join().unwrap();
3737+ }
3838+3939+ println!("Jobs done: {}", status.lock().unwrap().jobs_done);
4040+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4141+}
+62
solutions/20_threads/threads3.rs
···11+use std::{sync::mpsc, thread, time::Duration};
22+33+struct Queue {
44+ first_half: Vec<u32>,
55+ second_half: Vec<u32>,
66+}
77+88+impl Queue {
99+ fn new() -> Self {
1010+ Self {
1111+ first_half: vec![1, 2, 3, 4, 5],
1212+ second_half: vec![6, 7, 8, 9, 10],
1313+ }
1414+ }
1515+}
1616+1717+fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
1818+ // Clone the sender `tx` first.
1919+ let tx_clone = tx.clone();
2020+ thread::spawn(move || {
2121+ for val in q.first_half {
2222+ println!("Sending {val:?}");
2323+ // Then use the clone in the first thread. This means that
2424+ // `tx_clone` is moved to the first thread and `tx` to the second.
2525+ tx_clone.send(val).unwrap();
2626+ thread::sleep(Duration::from_millis(250));
2727+ }
2828+ });
2929+3030+ thread::spawn(move || {
3131+ for val in q.second_half {
3232+ println!("Sending {val:?}");
3333+ tx.send(val).unwrap();
3434+ thread::sleep(Duration::from_millis(250));
3535+ }
3636+ });
3737+}
3838+3939+fn main() {
4040+ // You can optionally experiment here.
4141+}
4242+4343+#[cfg(test)]
4444+mod tests {
4545+ use super::*;
4646+4747+ #[test]
4848+ fn threads3() {
4949+ let (tx, rx) = mpsc::channel();
5050+ let queue = Queue::new();
5151+5252+ send_tx(queue, tx);
5353+5454+ let mut received = Vec::with_capacity(10);
5555+ for value in rx {
5656+ received.push(value);
5757+ }
5858+5959+ received.sort();
6060+ assert_eq!(received, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
6161+ }
6262+}
···11+// Moved the macro definition to be before its call.
22+macro_rules! my_macro {
33+ () => {
44+ println!("Check out my macro!");
55+ };
66+}
77+88+fn main() {
99+ my_macro!();
1010+}
···11+// Added semicolons to separate the macro arms.
22+#[rustfmt::skip]
33+macro_rules! my_macro {
44+ () => {
55+ println!("Check out my macro!");
66+ };
77+ ($val:expr) => {
88+ println!("Look at this other macro: {}", $val);
99+ };
1010+}
1111+1212+fn main() {
1313+ my_macro!();
1414+ my_macro!(7777);
1515+}
+17
solutions/22_clippy/clippy1.rs
···11+// The Clippy tool is a collection of lints to analyze your code so you can
22+// catch common mistakes and improve your Rust code.
33+//
44+// For these exercises, the code will fail to compile when there are Clippy
55+// warnings. Check Clippy's suggestions from the output to solve the exercise.
66+77+use std::f32::consts::PI;
88+99+fn main() {
1010+ // Use the more accurate `PI` constant.
1111+ let pi = PI;
1212+ let radius: f32 = 5.0;
1313+1414+ let area = pi * radius.powi(2);
1515+1616+ println!("The area of a circle with radius {radius:.2} is {area:.5}");
1717+}
+10
solutions/22_clippy/clippy2.rs
···11+fn main() {
22+ let mut res = 42;
33+ let option = Some(12);
44+ // Use `if-let` instead of iteration.
55+ if let Some(x) = option {
66+ res += x;
77+ }
88+99+ println!("{res}");
1010+}
+31
solutions/22_clippy/clippy3.rs
···11+use std::mem;
22+33+#[rustfmt::skip]
44+#[allow(unused_variables, unused_assignments)]
55+fn main() {
66+ let my_option: Option<()> = None;
77+ // `unwrap` of an `Option` after checking if it is `None` will panic.
88+ // Use `if-let` instead.
99+ if let Some(value) = my_option {
1010+ println!("{value:?}");
1111+ }
1212+1313+ // A comma was missing.
1414+ let my_arr = &[
1515+ -1, -2, -3,
1616+ -4, -5, -6,
1717+ ];
1818+ println!("My array! Here it is: {:?}", my_arr);
1919+2020+ let mut my_empty_vec = vec![1, 2, 3, 4, 5];
2121+ // `resize` mutates a vector instead of returning a new one.
2222+ // `resize(0, …)` clears a vector, so it is better to use `clear`.
2323+ my_empty_vec.clear();
2424+ println!("This Vec is empty, see? {my_empty_vec:?}");
2525+2626+ let mut value_a = 45;
2727+ let mut value_b = 66;
2828+ // Use `mem::swap` to correctly swap two values.
2929+ mem::swap(&mut value_a, &mut value_b);
3030+ println!("value a: {}; value b: {}", value_a, value_b);
3131+}
+60
solutions/23_conversions/as_ref_mut.rs
···11+// AsRef and AsMut allow for cheap reference-to-reference conversions. Read more
22+// about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html and
33+// https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
44+55+// Obtain the number of bytes (not characters) in the given argument
66+// (`.len()` returns the number of bytes in a string).
77+fn byte_counter<T: AsRef<str>>(arg: T) -> usize {
88+ arg.as_ref().len()
99+}
1010+1111+// Obtain the number of characters (not bytes) in the given argument.
1212+fn char_counter<T: AsRef<str>>(arg: T) -> usize {
1313+ arg.as_ref().chars().count()
1414+}
1515+1616+// Squares a number using `as_mut()`.
1717+fn num_sq<T: AsMut<u32>>(arg: &mut T) {
1818+ let arg = arg.as_mut();
1919+ *arg *= *arg;
2020+}
2121+2222+fn main() {
2323+ // You can optionally experiment here.
2424+}
2525+2626+#[cfg(test)]
2727+mod tests {
2828+ use super::*;
2929+3030+ #[test]
3131+ fn different_counts() {
3232+ let s = "Café au lait";
3333+ assert_ne!(char_counter(s), byte_counter(s));
3434+ }
3535+3636+ #[test]
3737+ fn same_counts() {
3838+ let s = "Cafe au lait";
3939+ assert_eq!(char_counter(s), byte_counter(s));
4040+ }
4141+4242+ #[test]
4343+ fn different_counts_using_string() {
4444+ let s = String::from("Café au lait");
4545+ assert_ne!(char_counter(s.clone()), byte_counter(s));
4646+ }
4747+4848+ #[test]
4949+ fn same_counts_using_string() {
5050+ let s = String::from("Cafe au lait");
5151+ assert_eq!(char_counter(s.clone()), byte_counter(s));
5252+ }
5353+5454+ #[test]
5555+ fn mut_box() {
5656+ let mut num: Box<u32> = Box::new(3);
5757+ num_sq(&mut num);
5858+ assert_eq!(*num, 9);
5959+ }
6060+}
+136
solutions/23_conversions/from_into.rs
···11+// The `From` trait is used for value-to-value conversions. If `From` is
22+// implemented, an implementation of `Into` is automatically provided.
33+// You can read more about it in the documentation:
44+// https://doc.rust-lang.org/std/convert/trait.From.html
55+66+#[derive(Debug)]
77+struct Person {
88+ name: String,
99+ age: u8,
1010+}
1111+1212+// We implement the Default trait to use it as a fallback when the provided
1313+// string is not convertible into a `Person` object.
1414+impl Default for Person {
1515+ fn default() -> Self {
1616+ Self {
1717+ name: String::from("John"),
1818+ age: 30,
1919+ }
2020+ }
2121+}
2222+2323+impl From<&str> for Person {
2424+ fn from(s: &str) -> Self {
2525+ let mut split = s.split(',');
2626+ let (Some(name), Some(age), None) = (split.next(), split.next(), split.next()) else {
2727+ // ^^^^ there should be no third element
2828+ return Self::default();
2929+ };
3030+3131+ if name.is_empty() {
3232+ return Self::default();
3333+ }
3434+3535+ let Ok(age) = age.parse() else {
3636+ return Self::default();
3737+ };
3838+3939+ Self {
4040+ name: name.into(),
4141+ age,
4242+ }
4343+ }
4444+}
4545+4646+fn main() {
4747+ // Use the `from` function.
4848+ let p1 = Person::from("Mark,20");
4949+ println!("{p1:?}");
5050+5151+ // Since `From` is implemented for Person, we are able to use `Into`.
5252+ let p2: Person = "Gerald,70".into();
5353+ println!("{p2:?}");
5454+}
5555+5656+#[cfg(test)]
5757+mod tests {
5858+ use super::*;
5959+6060+ #[test]
6161+ fn test_default() {
6262+ let dp = Person::default();
6363+ assert_eq!(dp.name, "John");
6464+ assert_eq!(dp.age, 30);
6565+ }
6666+6767+ #[test]
6868+ fn test_bad_convert() {
6969+ let p = Person::from("");
7070+ assert_eq!(p.name, "John");
7171+ assert_eq!(p.age, 30);
7272+ }
7373+7474+ #[test]
7575+ fn test_good_convert() {
7676+ let p = Person::from("Mark,20");
7777+ assert_eq!(p.name, "Mark");
7878+ assert_eq!(p.age, 20);
7979+ }
8080+8181+ #[test]
8282+ fn test_bad_age() {
8383+ let p = Person::from("Mark,twenty");
8484+ assert_eq!(p.name, "John");
8585+ assert_eq!(p.age, 30);
8686+ }
8787+8888+ #[test]
8989+ fn test_missing_comma_and_age() {
9090+ let p: Person = Person::from("Mark");
9191+ assert_eq!(p.name, "John");
9292+ assert_eq!(p.age, 30);
9393+ }
9494+9595+ #[test]
9696+ fn test_missing_age() {
9797+ let p: Person = Person::from("Mark,");
9898+ assert_eq!(p.name, "John");
9999+ assert_eq!(p.age, 30);
100100+ }
101101+102102+ #[test]
103103+ fn test_missing_name() {
104104+ let p: Person = Person::from(",1");
105105+ assert_eq!(p.name, "John");
106106+ assert_eq!(p.age, 30);
107107+ }
108108+109109+ #[test]
110110+ fn test_missing_name_and_age() {
111111+ let p: Person = Person::from(",");
112112+ assert_eq!(p.name, "John");
113113+ assert_eq!(p.age, 30);
114114+ }
115115+116116+ #[test]
117117+ fn test_missing_name_and_invalid_age() {
118118+ let p: Person = Person::from(",one");
119119+ assert_eq!(p.name, "John");
120120+ assert_eq!(p.age, 30);
121121+ }
122122+123123+ #[test]
124124+ fn test_trailing_comma() {
125125+ let p: Person = Person::from("Mike,32,");
126126+ assert_eq!(p.name, "John");
127127+ assert_eq!(p.age, 30);
128128+ }
129129+130130+ #[test]
131131+ fn test_trailing_comma_and_some_string() {
132132+ let p: Person = Person::from("Mike,32,dog");
133133+ assert_eq!(p.name, "John");
134134+ assert_eq!(p.age, 30);
135135+ }
136136+}
+117
solutions/23_conversions/from_str.rs
···11+// This is similar to the previous `from_into` exercise. But this time, we'll
22+// implement `FromStr` and return errors instead of falling back to a default
33+// value. Additionally, upon implementing `FromStr`, you can use the `parse`
44+// method on strings to generate an object of the implementor type. You can read
55+// more about it in the documentation:
66+// https://doc.rust-lang.org/std/str/trait.FromStr.html
77+88+use std::num::ParseIntError;
99+use std::str::FromStr;
1010+1111+#[derive(Debug, PartialEq)]
1212+struct Person {
1313+ name: String,
1414+ age: u8,
1515+}
1616+1717+// We will use this error type for the `FromStr` implementation.
1818+#[derive(Debug, PartialEq)]
1919+enum ParsePersonError {
2020+ // Incorrect number of fields
2121+ BadLen,
2222+ // Empty name field
2323+ NoName,
2424+ // Wrapped error from parse::<u8>()
2525+ ParseInt(ParseIntError),
2626+}
2727+2828+impl FromStr for Person {
2929+ type Err = ParsePersonError;
3030+3131+ fn from_str(s: &str) -> Result<Self, Self::Err> {
3232+ let mut split = s.split(',');
3333+ let (Some(name), Some(age), None) = (split.next(), split.next(), split.next()) else {
3434+ // ^^^^ there should be no third element
3535+ return Err(ParsePersonError::BadLen);
3636+ };
3737+3838+ if name.is_empty() {
3939+ return Err(ParsePersonError::NoName);
4040+ }
4141+4242+ let age = age.parse().map_err(ParsePersonError::ParseInt)?;
4343+4444+ Ok(Self {
4545+ name: name.into(),
4646+ age,
4747+ })
4848+ }
4949+}
5050+5151+fn main() {
5252+ let p = "Mark,20".parse::<Person>();
5353+ println!("{p:?}");
5454+}
5555+5656+#[cfg(test)]
5757+mod tests {
5858+ use super::*;
5959+ use ParsePersonError::*;
6060+6161+ #[test]
6262+ fn empty_input() {
6363+ assert_eq!("".parse::<Person>(), Err(BadLen));
6464+ }
6565+6666+ #[test]
6767+ fn good_input() {
6868+ let p = "John,32".parse::<Person>();
6969+ assert!(p.is_ok());
7070+ let p = p.unwrap();
7171+ assert_eq!(p.name, "John");
7272+ assert_eq!(p.age, 32);
7373+ }
7474+7575+ #[test]
7676+ fn missing_age() {
7777+ assert!(matches!("John,".parse::<Person>(), Err(ParseInt(_))));
7878+ }
7979+8080+ #[test]
8181+ fn invalid_age() {
8282+ assert!(matches!("John,twenty".parse::<Person>(), Err(ParseInt(_))));
8383+ }
8484+8585+ #[test]
8686+ fn missing_comma_and_age() {
8787+ assert_eq!("John".parse::<Person>(), Err(BadLen));
8888+ }
8989+9090+ #[test]
9191+ fn missing_name() {
9292+ assert_eq!(",1".parse::<Person>(), Err(NoName));
9393+ }
9494+9595+ #[test]
9696+ fn missing_name_and_age() {
9797+ assert!(matches!(",".parse::<Person>(), Err(NoName | ParseInt(_))));
9898+ }
9999+100100+ #[test]
101101+ fn missing_name_and_invalid_age() {
102102+ assert!(matches!(
103103+ ",one".parse::<Person>(),
104104+ Err(NoName | ParseInt(_)),
105105+ ));
106106+ }
107107+108108+ #[test]
109109+ fn trailing_comma() {
110110+ assert_eq!("John,32,".parse::<Person>(), Err(BadLen));
111111+ }
112112+113113+ #[test]
114114+ fn trailing_comma_and_some_string() {
115115+ assert_eq!("John,32,man".parse::<Person>(), Err(BadLen));
116116+ }
117117+}
+193
solutions/23_conversions/try_from_into.rs
···11+// `TryFrom` is a simple and safe type conversion that may fail in a controlled
22+// way under some circumstances. Basically, this is the same as `From`. The main
33+// difference is that this should return a `Result` type instead of the target
44+// type itself. You can read more about it in the documentation:
55+// https://doc.rust-lang.org/std/convert/trait.TryFrom.html
66+77+#![allow(clippy::useless_vec)]
88+use std::convert::{TryFrom, TryInto};
99+1010+#[derive(Debug, PartialEq)]
1111+struct Color {
1212+ red: u8,
1313+ green: u8,
1414+ blue: u8,
1515+}
1616+1717+// We will use this error type for the `TryFrom` conversions.
1818+#[derive(Debug, PartialEq)]
1919+enum IntoColorError {
2020+ // Incorrect length of slice
2121+ BadLen,
2222+ // Integer conversion error
2323+ IntConversion,
2424+}
2525+2626+impl TryFrom<(i16, i16, i16)> for Color {
2727+ type Error = IntoColorError;
2828+2929+ fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
3030+ let (Ok(red), Ok(green), Ok(blue)) = (
3131+ u8::try_from(tuple.0),
3232+ u8::try_from(tuple.1),
3333+ u8::try_from(tuple.2),
3434+ ) else {
3535+ return Err(IntoColorError::IntConversion);
3636+ };
3737+3838+ Ok(Self { red, green, blue })
3939+ }
4040+}
4141+4242+impl TryFrom<[i16; 3]> for Color {
4343+ type Error = IntoColorError;
4444+4545+ fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
4646+ // Reuse the implementation for a tuple.
4747+ Self::try_from((arr[0], arr[1], arr[2]))
4848+ }
4949+}
5050+5151+impl TryFrom<&[i16]> for Color {
5252+ type Error = IntoColorError;
5353+5454+ fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
5555+ // Check the length.
5656+ if slice.len() != 3 {
5757+ return Err(IntoColorError::BadLen);
5858+ }
5959+6060+ // Reuse the implementation for a tuple.
6161+ Self::try_from((slice[0], slice[1], slice[2]))
6262+ }
6363+}
6464+6565+fn main() {
6666+ // Using the `try_from` function.
6767+ let c1 = Color::try_from((183, 65, 14));
6868+ println!("{c1:?}");
6969+7070+ // Since `TryFrom` is implemented for `Color`, we can use `TryInto`.
7171+ let c2: Result<Color, _> = [183, 65, 14].try_into();
7272+ println!("{c2:?}");
7373+7474+ let v = vec![183, 65, 14];
7575+ // With slice we should use the `try_from` function
7676+ let c3 = Color::try_from(&v[..]);
7777+ println!("{c3:?}");
7878+ // or put the slice within round brackets and use `try_into`.
7979+ let c4: Result<Color, _> = (&v[..]).try_into();
8080+ println!("{c4:?}");
8181+}
8282+8383+#[cfg(test)]
8484+mod tests {
8585+ use super::*;
8686+ use IntoColorError::*;
8787+8888+ #[test]
8989+ fn test_tuple_out_of_range_positive() {
9090+ assert_eq!(Color::try_from((256, 1000, 10000)), Err(IntConversion));
9191+ }
9292+9393+ #[test]
9494+ fn test_tuple_out_of_range_negative() {
9595+ assert_eq!(Color::try_from((-1, -10, -256)), Err(IntConversion));
9696+ }
9797+9898+ #[test]
9999+ fn test_tuple_sum() {
100100+ assert_eq!(Color::try_from((-1, 255, 255)), Err(IntConversion));
101101+ }
102102+103103+ #[test]
104104+ fn test_tuple_correct() {
105105+ let c: Result<Color, _> = (183, 65, 14).try_into();
106106+ assert!(c.is_ok());
107107+ assert_eq!(
108108+ c.unwrap(),
109109+ Color {
110110+ red: 183,
111111+ green: 65,
112112+ blue: 14,
113113+ }
114114+ );
115115+ }
116116+117117+ #[test]
118118+ fn test_array_out_of_range_positive() {
119119+ let c: Result<Color, _> = [1000, 10000, 256].try_into();
120120+ assert_eq!(c, Err(IntConversion));
121121+ }
122122+123123+ #[test]
124124+ fn test_array_out_of_range_negative() {
125125+ let c: Result<Color, _> = [-10, -256, -1].try_into();
126126+ assert_eq!(c, Err(IntConversion));
127127+ }
128128+129129+ #[test]
130130+ fn test_array_sum() {
131131+ let c: Result<Color, _> = [-1, 255, 255].try_into();
132132+ assert_eq!(c, Err(IntConversion));
133133+ }
134134+135135+ #[test]
136136+ fn test_array_correct() {
137137+ let c: Result<Color, _> = [183, 65, 14].try_into();
138138+ assert!(c.is_ok());
139139+ assert_eq!(
140140+ c.unwrap(),
141141+ Color {
142142+ red: 183,
143143+ green: 65,
144144+ blue: 14
145145+ }
146146+ );
147147+ }
148148+149149+ #[test]
150150+ fn test_slice_out_of_range_positive() {
151151+ let arr = [10000, 256, 1000];
152152+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
153153+ }
154154+155155+ #[test]
156156+ fn test_slice_out_of_range_negative() {
157157+ let arr = [-256, -1, -10];
158158+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
159159+ }
160160+161161+ #[test]
162162+ fn test_slice_sum() {
163163+ let arr = [-1, 255, 255];
164164+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
165165+ }
166166+167167+ #[test]
168168+ fn test_slice_correct() {
169169+ let v = vec![183, 65, 14];
170170+ let c: Result<Color, _> = Color::try_from(&v[..]);
171171+ assert!(c.is_ok());
172172+ assert_eq!(
173173+ c.unwrap(),
174174+ Color {
175175+ red: 183,
176176+ green: 65,
177177+ blue: 14,
178178+ }
179179+ );
180180+ }
181181+182182+ #[test]
183183+ fn test_slice_excess_length() {
184184+ let v = vec![0, 0, 0, 0];
185185+ assert_eq!(Color::try_from(&v[..]), Err(BadLen));
186186+ }
187187+188188+ #[test]
189189+ fn test_slice_insufficient_length() {
190190+ let v = vec![0, 0];
191191+ assert_eq!(Color::try_from(&v[..]), Err(BadLen));
192192+ }
193193+}
+24
solutions/23_conversions/using_as.rs
···11+// Type casting in Rust is done via the usage of the `as` operator.
22+// Note that the `as` operator is not only used when type casting. It also helps
33+// with renaming imports.
44+55+fn average(values: &[f64]) -> f64 {
66+ let total = values.iter().sum::<f64>();
77+ total / values.len() as f64
88+ // ^^^^^^
99+}
1010+1111+fn main() {
1212+ let values = [3.5, 0.3, 13.0, 11.7];
1313+ println!("{}", average(&values));
1414+}
1515+1616+#[cfg(test)]
1717+mod tests {
1818+ use super::*;
1919+2020+ #[test]
2121+ fn returns_proper_type_and_value() {
2222+ assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
2323+ }
2424+}
+6
solutions/README.md
···11+# Official Rustlings solutions
22+33+Before you finish an exercise, its solution file will only contain an empty `main` function.
44+The content of this file will be automatically replaced by the actual solution once you finish the exercise.
55+66+Note that these solutions are often only _one possibility_ to solve an exercise.
+30
solutions/quizzes/quiz1.rs
···11+// Mary is buying apples. The price of an apple is calculated as follows:
22+// - An apple costs 2 rustbucks.
33+// - However, if Mary buys more than 40 apples, the price of each apple in the
44+// entire order is reduced to only 1 rustbuck!
55+66+fn calculate_price_of_apples(n_apples: u64) -> u64 {
77+ if n_apples > 40 {
88+ n_apples
99+ } else {
1010+ 2 * n_apples
1111+ }
1212+}
1313+1414+fn main() {
1515+ // You can optionally experiment here.
1616+}
1717+1818+// Don't change the tests!
1919+#[cfg(test)]
2020+mod tests {
2121+ use super::*;
2222+2323+ #[test]
2424+ fn verify_test() {
2525+ assert_eq!(calculate_price_of_apples(35), 70);
2626+ assert_eq!(calculate_price_of_apples(40), 80);
2727+ assert_eq!(calculate_price_of_apples(41), 41);
2828+ assert_eq!(calculate_price_of_apples(65), 65);
2929+ }
3030+}
+90
solutions/quizzes/quiz2.rs
···11+// Let's build a little machine in the form of a function. As input, we're going
22+// to give a list of strings and commands. These commands determine what action
33+// is going to be applied to the string. It can either be:
44+// - Uppercase the string
55+// - Trim the string
66+// - Append "bar" to the string a specified amount of times
77+//
88+// The exact form of this will be:
99+// - The input is going to be a vector of 2-length tuples,
1010+// the first element is the string, the second one is the command.
1111+// - The output element is going to be a vector of strings.
1212+1313+enum Command {
1414+ Uppercase,
1515+ Trim,
1616+ Append(usize),
1717+}
1818+1919+mod my_module {
2020+ use super::Command;
2121+2222+ // The solution with a loop. Check out `transformer_iter` for a version
2323+ // with iterators.
2424+ pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
2525+ let mut output = Vec::new();
2626+2727+ for (string, command) in input {
2828+ // Create the new string.
2929+ let new_string = match command {
3030+ Command::Uppercase => string.to_uppercase(),
3131+ Command::Trim => string.trim().to_string(),
3232+ Command::Append(n) => string + &"bar".repeat(n),
3333+ };
3434+3535+ // Push the new string to the output vector.
3636+ output.push(new_string);
3737+ }
3838+3939+ output
4040+ }
4141+4242+ // Equivalent to `transform` but uses an iterator instead of a loop for
4343+ // comparison. Don't worry, we will practice iterators later ;)
4444+ pub fn transformer_iter(input: Vec<(String, Command)>) -> Vec<String> {
4545+ input
4646+ .into_iter()
4747+ .map(|(string, command)| match command {
4848+ Command::Uppercase => string.to_uppercase(),
4949+ Command::Trim => string.trim().to_string(),
5050+ Command::Append(n) => string + &"bar".repeat(n),
5151+ })
5252+ .collect()
5353+ }
5454+}
5555+5656+fn main() {
5757+ // You can optionally experiment here.
5858+}
5959+6060+#[cfg(test)]
6161+mod tests {
6262+ // Import `transformer`.
6363+ use super::my_module::transformer;
6464+6565+ use super::my_module::transformer_iter;
6666+ use super::Command;
6767+6868+ #[test]
6969+ fn it_works() {
7070+ for transformer in [transformer, transformer_iter] {
7171+ let input = vec![
7272+ ("hello".to_string(), Command::Uppercase),
7373+ (" all roads lead to rome! ".to_string(), Command::Trim),
7474+ ("foo".to_string(), Command::Append(1)),
7575+ ("bar".to_string(), Command::Append(5)),
7676+ ];
7777+ let output = transformer(input);
7878+7979+ assert_eq!(
8080+ output,
8181+ [
8282+ "HELLO",
8383+ "all roads lead to rome!",
8484+ "foobar",
8585+ "barbarbarbarbarbar",
8686+ ]
8787+ );
8888+ }
8989+ }
9090+}
+65
solutions/quizzes/quiz3.rs
···11+// An imaginary magical school has a new report card generation system written
22+// in Rust! Currently, the system only supports creating report cards where the
33+// student's grade is represented numerically (e.g. 1.0 -> 5.5). However, the
44+// school also issues alphabetical grades (A+ -> F-) and needs to be able to
55+// print both types of report card!
66+//
77+// Make the necessary code changes in the struct `ReportCard` and the impl
88+// block to support alphabetical report cards in addition to numerical ones.
99+1010+use std::fmt::Display;
1111+1212+// Make the struct generic over `T`.
1313+struct ReportCard<T> {
1414+ // ^^^
1515+ grade: T,
1616+ // ^
1717+ student_name: String,
1818+ student_age: u8,
1919+}
2020+2121+// To be able to print the grade, it has to implement the `Display` trait.
2222+impl<T: Display> ReportCard<T> {
2323+ // ^^^^^^^ require that `T` implements `Display`.
2424+ fn print(&self) -> String {
2525+ format!(
2626+ "{} ({}) - achieved a grade of {}",
2727+ &self.student_name, &self.student_age, &self.grade,
2828+ )
2929+ }
3030+}
3131+3232+fn main() {
3333+ // You can optionally experiment here.
3434+}
3535+3636+#[cfg(test)]
3737+mod tests {
3838+ use super::*;
3939+4040+ #[test]
4141+ fn generate_numeric_report_card() {
4242+ let report_card = ReportCard {
4343+ grade: 2.1,
4444+ student_name: "Tom Wriggle".to_string(),
4545+ student_age: 12,
4646+ };
4747+ assert_eq!(
4848+ report_card.print(),
4949+ "Tom Wriggle (12) - achieved a grade of 2.1",
5050+ );
5151+ }
5252+5353+ #[test]
5454+ fn generate_alphabetic_report_card() {
5555+ let report_card = ReportCard {
5656+ grade: "A+",
5757+ student_name: "Gary Plotter".to_string(),
5858+ student_age: 11,
5959+ };
6060+ assert_eq!(
6161+ report_card.print(),
6262+ "Gary Plotter (11) - achieved a grade of A+",
6363+ );
6464+ }
6565+}