···11+DON'T EDIT THIS FILE!
22+33+intro2
44+55+intro1
+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"
+8
exercises/00_intro/README.md
···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+ printline!("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+ 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;
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;
44+55+ println!("Number {x}");
66+}
+8
exercises/01_variables/variables4.rs
···11+// TODO: Fix the compiler error.
22+fn main() {
33+ let 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+ 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 = 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)
+5
exercises/02_functions/functions1.rs
···11+// TODO: Add some function with the name `call_me` without arguments or a return value.
22+33+fn main() {
44+ call_me(); // Don't change this line
55+}
+10
exercises/02_functions/functions2.rs
···11+// TODO: Add the missing type of the argument `num` after the colon `:`.
22+fn call_me(num:) {
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();
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) -> {
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)
+32
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+}
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+}
+37
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 {
66+ 1
77+ }
88+}
99+1010+fn main() {
1111+ // You can optionally experiment here.
1212+}
1313+1414+// TODO: Read the tests to understand the desired behavior.
1515+// Make all tests pass without changing them.
1616+#[cfg(test)]
1717+mod tests {
1818+ use super::*;
1919+2020+ #[test]
2121+ fn yummy_food() {
2222+ // This means that calling `picky_eater` with the argument "food" should return "Yummy!".
2323+ assert_eq!(picky_eater("strawberry"), "Yummy!");
2424+ }
2525+2626+ #[test]
2727+ fn neutral_food() {
2828+ assert_eq!(picky_eater("potato"), "I guess I can eat that.");
2929+ }
3030+3131+ #[test]
3232+ fn default_disliked_food() {
3333+ assert_eq!(picky_eater("broccoli"), "No thanks!");
3434+ assert_eq!(picky_eater("gummy bears"), "No thanks!");
3535+ assert_eq!(picky_eater("literally anything"), "No thanks!");
3636+ }
3737+}
···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)
+15
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+ if is_evening {
1313+ println!("Good evening!");
1414+ }
1515+}
+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 = '';
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 = ???
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+}
+16
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+1414+ assert_eq!([2, 3, 4], nice_slice);
1515+ }
1616+}
+8
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+77+ println!("{name} is {age} years old");
88+}
+17
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+1515+ assert_eq!(second, 2, "This is not the 2nd number in the tuple!");
1616+ }
1717+}
+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)
+24
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+88+ (a, v)
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 test_array_and_vec_similarity() {
2121+ let (a, v) = array_and_vec();
2222+ assert_eq!(a, *v);
2323+ }
2424+}
+60
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+ }
88+99+ output
1010+}
1111+1212+fn vec_map_example(input: &[i32]) -> Vec<i32> {
1313+ // An example of collecting a vector after mapping.
1414+ // We map each element of the `input` slice to its value plus 1.
1515+ // If the input is `[1, 2, 3]`, the output is `[2, 3, 4]`.
1616+ input.iter().map(|element| element + 1).collect()
1717+}
1818+1919+fn vec_map(input: &[i32]) -> Vec<i32> {
2020+ // TODO: Here, we also want to multiply each element in the `input` slice
2121+ // by 2, but with iterator mapping instead of manually pushing into an empty
2222+ // vector.
2323+ // See the example in the function `vec_map_example` above.
2424+ input
2525+ .iter()
2626+ .map(|element| {
2727+ // ???
2828+ })
2929+ .collect()
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 test_vec_loop() {
4242+ let input = [2, 4, 6, 8, 10];
4343+ let ans = vec_loop(&input);
4444+ assert_eq!(ans, [4, 8, 12, 16, 20]);
4545+ }
4646+4747+ #[test]
4848+ fn test_vec_map_example() {
4949+ let input = [1, 2, 3];
5050+ let ans = vec_map_example(&input);
5151+ assert_eq!(ans, [2, 3, 4]);
5252+ }
5353+5454+ #[test]
5555+ fn test_vec_map() {
5656+ let input = [2, 4, 6, 8, 10];
5757+ let ans = vec_map(&input);
5858+ assert_eq!(ans, [4, 8, 12, 16, 20]);
5959+ }
6060+}
+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 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);
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(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+ let z = &mut x;
1414+ y.push(42);
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)
+47
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+}
55+66+struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */);
77+88+#[derive(Debug)]
99+struct UnitStruct;
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 regular_structs() {
2121+ // TODO: Instantiate a regular struct.
2222+ // let green =
2323+2424+ assert_eq!(green.red, 0);
2525+ assert_eq!(green.green, 255);
2626+ assert_eq!(green.blue, 0);
2727+ }
2828+2929+ #[test]
3030+ fn tuple_structs() {
3131+ // TODO: Instantiate a tuple struct.
3232+ // let green =
3333+3434+ assert_eq!(green.0, 0);
3535+ assert_eq!(green.1, 255);
3636+ assert_eq!(green.2, 0);
3737+ }
3838+3939+ #[test]
4040+ fn unit_structs() {
4141+ // TODO: Instantiate a unit struct.
4242+ // let unit_struct =
4343+ let message = format!("{unit_struct:?}s are fun!");
4444+4545+ assert_eq!(message, "UnitStructs are fun!");
4646+ }
4747+}
+47
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+3939+ assert_eq!(your_order.name, "Hacker in Rust");
4040+ assert_eq!(your_order.year, order_template.year);
4141+ assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
4242+ assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
4343+ assert_eq!(your_order.made_by_email, order_template.made_by_email);
4444+ assert_eq!(your_order.item_number, order_template.item_number);
4545+ assert_eq!(your_order.count, 1);
4646+ }
4747+}
+87
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) {
2828+ // TODO: Read the tests that use this method to find out when a package
2929+ // is considered international.
3030+ }
3131+3232+ // TODO: Add the correct return type to the function signature.
3333+ fn get_fees(&self, cents_per_gram: u32) {
3434+ // TODO: Calculate the package's fees.
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+ #[should_panic]
4848+ fn fail_creating_weightless_package() {
4949+ let sender_country = String::from("Spain");
5050+ let recipient_country = String::from("Austria");
5151+5252+ Package::new(sender_country, recipient_country, 5);
5353+ }
5454+5555+ #[test]
5656+ fn create_international_package() {
5757+ let sender_country = String::from("Spain");
5858+ let recipient_country = String::from("Russia");
5959+6060+ let package = Package::new(sender_country, recipient_country, 1200);
6161+6262+ assert!(package.is_international());
6363+ }
6464+6565+ #[test]
6666+ fn create_local_package() {
6767+ let sender_country = String::from("Canada");
6868+ let recipient_country = sender_country.clone();
6969+7070+ let package = Package::new(sender_country, recipient_country, 1200);
7171+7272+ assert!(!package.is_international());
7373+ }
7474+7575+ #[test]
7676+ fn calculate_transport_fees() {
7777+ let sender_country = String::from("Spain");
7878+ let recipient_country = String::from("Spain");
7979+8080+ let cents_per_gram = 3;
8181+8282+ let package = Package::new(sender_country, recipient_country, 1500);
8383+8484+ assert_eq!(package.get_fees(cents_per_gram), 4500);
8585+ assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
8686+ }
8787+}
+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)
+12
exercises/08_enums/enums1.rs
···11+#[derive(Debug)]
22+enum Message {
33+ // TODO: Define a few types of messages as used below.
44+}
55+66+fn main() {
77+ println!("{:?}", Message::Resize);
88+ println!("{:?}", Message::Move);
99+ println!("{:?}", Message::Echo);
1010+ println!("{:?}", Message::ChangeColor);
1111+ println!("{:?}", Message::Quit);
1212+}
···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"
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+}
+45
exercises/09_strings/strings3.rs
···11+fn trim_me(input: &str) -> &str {
22+ // TODO: Remove whitespace from both ends of a string.
33+}
44+55+fn compose_me(input: &str) -> String {
66+ // TODO: Add " world!" to the string! There are multiple ways to do this.
77+}
88+99+fn replace_me(input: &str) -> String {
1010+ // TODO: Replace "cars" in the string with "balloons".
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 trim_a_string() {
2323+ assert_eq!(trim_me("Hello! "), "Hello!");
2424+ assert_eq!(trim_me(" What's up!"), "What's up!");
2525+ assert_eq!(trim_me(" Hola! "), "Hola!");
2626+ }
2727+2828+ #[test]
2929+ fn compose_a_string() {
3030+ assert_eq!(compose_me("Hello"), "Hello world!");
3131+ assert_eq!(compose_me("Goodbye"), "Goodbye world!");
3232+ }
3333+3434+ #[test]
3535+ fn replace_a_string() {
3636+ assert_eq!(
3737+ replace_me("I think cars are cool"),
3838+ "I think balloons are cool",
3939+ );
4040+ assert_eq!(
4141+ replace_me("I love to look at cars"),
4242+ "I love to look at balloons",
4343+ );
4444+ }
4545+}
+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+ placeholder("blue");
1717+1818+ placeholder("red".to_string());
1919+2020+ placeholder(String::from("hi"));
2121+2222+ placeholder("rust is fun!".to_owned());
2323+2424+ placeholder("nice weather".into());
2525+2626+ placeholder(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+ placeholder(&String::from("abc")[0..1]);
3131+3232+ placeholder(" hello there ".trim());
3333+3434+ placeholder("Happy Monday!".replace("Mon", "Tues"));
3535+3636+ placeholder("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+ fn make_sausage() {
99+ get_secret_recipe();
1010+ println!("sausage!");
1111+ }
1212+}
1313+1414+fn main() {
1515+ sausage_factory::make_sausage();
1616+}
+26
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+99+ mod fruits {
1010+ pub const PEAR: &str = "Pear";
1111+ pub const APPLE: &str = "Apple";
1212+ }
1313+1414+ mod veggies {
1515+ pub const CUCUMBER: &str = "Cucumber";
1616+ pub const CARROT: &str = "Carrot";
1717+ }
1818+}
1919+2020+fn main() {
2121+ println!(
2222+ "favorite snacks: {} and {}",
2323+ delicious_snacks::fruit,
2424+ delicious_snacks::veggie,
2525+ );
2626+}
+13
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+88+fn main() {
99+ match SystemTime::now().duration_since(UNIX_EPOCH) {
1010+ Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
1111+ Err(_) => panic!("SystemTime before UNIX EPOCH!"),
1212+ }
1313+}
+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)
+40
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+1313+ // Two bananas are already given for you :)
1414+ basket.insert(String::from("banana"), 2);
1515+1616+ // TODO: Put more fruits in your basket.
1717+1818+ basket
1919+}
2020+2121+fn main() {
2222+ // You can optionally experiment here.
2323+}
2424+2525+#[cfg(test)]
2626+mod tests {
2727+ use super::*;
2828+2929+ #[test]
3030+ fn at_least_three_types_of_fruits() {
3131+ let basket = fruit_basket();
3232+ assert!(basket.len() >= 3);
3333+ }
3434+3535+ #[test]
3636+ fn at_least_five_fruits() {
3737+ let basket = fruit_basket();
3838+ assert!(basket.values().sum::<u32>() >= 5);
3939+ }
4040+}
+97
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+ }
3636+}
3737+3838+fn main() {
3939+ // You can optionally experiment here.
4040+}
4141+4242+#[cfg(test)]
4343+mod tests {
4444+ use super::*;
4545+4646+ // Don't modify this function!
4747+ fn get_fruit_basket() -> HashMap<Fruit, u32> {
4848+ let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
4949+ HashMap::from_iter(content)
5050+ }
5151+5252+ #[test]
5353+ fn test_given_fruits_are_not_modified() {
5454+ let mut basket = get_fruit_basket();
5555+ fruit_basket(&mut basket);
5656+ assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
5757+ assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
5858+ assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
5959+ }
6060+6161+ #[test]
6262+ fn at_least_five_types_of_fruits() {
6363+ let mut basket = get_fruit_basket();
6464+ fruit_basket(&mut basket);
6565+ let count_fruit_kinds = basket.len();
6666+ assert!(count_fruit_kinds >= 5);
6767+ }
6868+6969+ #[test]
7070+ fn greater_than_eleven_fruits() {
7171+ let mut basket = get_fruit_basket();
7272+ fruit_basket(&mut basket);
7373+ let count = basket.values().sum::<u32>();
7474+ assert!(count > 11);
7575+ }
7676+7777+ #[test]
7878+ fn all_fruit_types_in_basket() {
7979+ let fruit_kinds = [
8080+ Fruit::Apple,
8181+ Fruit::Banana,
8282+ Fruit::Mango,
8383+ Fruit::Lychee,
8484+ Fruit::Pineapple,
8585+ ];
8686+8787+ let mut basket = get_fruit_basket();
8888+ fruit_basket(&mut basket);
8989+9090+ for fruit_kind in fruit_kinds {
9191+ let Some(amount) = basket.get(&fruit_kind) else {
9292+ panic!("Fruit kind {fruit_kind:?} was not found in basket");
9393+ };
9494+ assert!(*amount > 0);
9595+ }
9696+ }
9797+}
+77
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+ }
3535+3636+ scores
3737+}
3838+3939+fn main() {
4040+ // You can optionally experiment here.
4141+}
4242+4343+#[cfg(test)]
4444+mod tests {
4545+ use super::*;
4646+4747+ const RESULTS: &str = "England,France,4,2
4848+France,Italy,3,1
4949+Poland,Spain,2,0
5050+Germany,England,2,1
5151+England,Spain,1,0";
5252+5353+ #[test]
5454+ fn build_scores() {
5555+ let scores = build_scores_table(RESULTS);
5656+5757+ assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
5858+ .into_iter()
5959+ .all(|team_name| scores.contains_key(team_name)));
6060+ }
6161+6262+ #[test]
6363+ fn validate_team_score_1() {
6464+ let scores = build_scores_table(RESULTS);
6565+ let team = scores.get("England").unwrap();
6666+ assert_eq!(team.goals_scored, 6);
6767+ assert_eq!(team.goals_conceded, 4);
6868+ }
6969+7070+ #[test]
7171+ fn validate_team_score_2() {
7272+ let scores = build_scores_table(RESULTS);
7373+ let team = scores.get("Spain").unwrap();
7474+ assert_eq!(team.goals_scored, 0);
7575+ assert_eq!(team.goals_conceded, 3);
7676+ }
7777+}
+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)
+36
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+}
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 raw_value() {
1919+ // TODO: Fix this test. How do you get the value contained in the
2020+ // Option?
2121+ let icecreams = maybe_icecream(12);
2222+2323+ assert_eq!(icecreams, 5); // Don't change this line.
2424+ }
2525+2626+ #[test]
2727+ fn check_icecream() {
2828+ assert_eq!(maybe_icecream(0), Some(5));
2929+ assert_eq!(maybe_icecream(9), Some(5));
3030+ assert_eq!(maybe_icecream(18), Some(5));
3131+ assert_eq!(maybe_icecream(22), Some(0));
3232+ assert_eq!(maybe_icecream(23), Some(0));
3333+ assert_eq!(maybe_icecream(24), None);
3434+ assert_eq!(maybe_icecream(25), None);
3535+ }
3636+}
+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+ 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+ 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(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) -> Option<String> {
88+ if name.is_empty() {
99+ // Empty names aren't allowed
1010+ None
1111+ } else {
1212+ Some(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+}
+31
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() {
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+}
···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() {
5252+ let pretend_user_input = "42";
5353+ let x: i64 = pretend_user_input.parse()?;
5454+ println!("output={:?}", PositiveNonzeroInteger::new(x)?);
5555+ Ok(())
5656+}
+89
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+}
3030+3131+#[derive(PartialEq, Debug)]
3232+struct PositiveNonzeroInteger(u64);
3333+3434+impl PositiveNonzeroInteger {
3535+ fn new(value: i64) -> Result<Self, CreationError> {
3636+ match value {
3737+ x if x < 0 => Err(CreationError::Negative),
3838+ 0 => Err(CreationError::Zero),
3939+ x => Ok(Self(x as u64)),
4040+ }
4141+ }
4242+4343+ fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
4444+ // TODO: change this to return an appropriate error instead of panicking
4545+ // when `parse()` returns an error.
4646+ let x: i64 = s.parse().unwrap();
4747+ Self::new(x).map_err(ParsePosNonzeroError::from_creation)
4848+ }
4949+}
5050+5151+fn main() {
5252+ // You can optionally experiment here.
5353+}
5454+5555+#[cfg(test)]
5656+mod test {
5757+ use super::*;
5858+5959+ #[test]
6060+ fn test_parse_error() {
6161+ assert!(matches!(
6262+ PositiveNonzeroInteger::parse("not a number"),
6363+ Err(ParsePosNonzeroError::ParseInt(_)),
6464+ ));
6565+ }
6666+6767+ #[test]
6868+ fn test_negative() {
6969+ assert_eq!(
7070+ PositiveNonzeroInteger::parse("-555"),
7171+ Err(ParsePosNonzeroError::Creation(CreationError::Negative)),
7272+ );
7373+ }
7474+7575+ #[test]
7676+ fn test_zero() {
7777+ assert_eq!(
7878+ PositiveNonzeroInteger::parse("0"),
7979+ Err(ParsePosNonzeroError::Creation(CreationError::Zero)),
8080+ );
8181+ }
8282+8383+ #[test]
8484+ fn test_positive() {
8585+ let x = PositiveNonzeroInteger::new(42).unwrap();
8686+ assert_eq!(x.0, 42);
8787+ assert_eq!(PositiveNonzeroInteger::parse("42"), Ok(x));
8888+ }
8989+}
+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::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 {
44+ value: u32,
55+}
66+77+// TODO: Adapt the struct's implementation to be generic over the wrapped value.
88+impl Wrapper {
99+ fn new(value: u32) -> 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)
+30
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+}
1010+1111+fn main() {
1212+ let s = String::from("Foo");
1313+ let s = s.append_bar();
1414+ println!("s: {s}");
1515+}
1616+1717+#[cfg(test)]
1818+mod tests {
1919+ use super::*;
2020+2121+ #[test]
2222+ fn is_foo_bar() {
2323+ assert_eq!(String::from("Foo").append_bar(), "FooBar");
2424+ }
2525+2626+ #[test]
2727+ fn is_bar_bar() {
2828+ assert_eq!(String::from("").append_bar().append_bar(), "BarBar");
2929+ }
3030+}
+22
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+fn main() {
99+ // You can optionally experiment here.
1010+}
1111+1212+#[cfg(test)]
1313+mod tests {
1414+ use super::*;
1515+1616+ #[test]
1717+ fn is_vec_pop_eq_bar() {
1818+ let mut foo = vec![String::from("Foo")].append_bar();
1919+ assert_eq!(foo.pop().unwrap(), "Bar");
2020+ assert_eq!(foo.pop().unwrap(), "Foo");
2121+ }
2222+}
+38
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+}
88+99+struct SomeSoftware {
1010+ version_number: i32,
1111+}
1212+1313+struct OtherSoftware {
1414+ version_number: String,
1515+}
1616+1717+impl Licensed for SomeSoftware {} // Don't edit this line.
1818+impl Licensed for OtherSoftware {} // Don't edit this line.
1919+2020+fn main() {
2121+ // You can optionally experiment here.
2222+}
2323+2424+#[cfg(test)]
2525+mod tests {
2626+ use super::*;
2727+2828+ #[test]
2929+ fn is_licensing_info_the_same() {
3030+ let licensing_info = "Default license";
3131+ let some_software = SomeSoftware { version_number: 1 };
3232+ let other_software = OtherSoftware {
3333+ version_number: "v2.0.0".to_string(),
3434+ };
3535+ assert_eq!(some_software.licensing_info(), licensing_info);
3636+ assert_eq!(other_software.licensing_info(), licensing_info);
3737+ }
3838+}
+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: ???, software2: ???) -> 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+}
+39
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(item: ???) -> bool {
2323+ item.some_function() && item.other_function()
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 test_some_func() {
3636+ assert!(some_func(SomeStruct));
3737+ assert!(some_func(OtherStruct));
3838+ }
3939+}
+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(x: &str, y: &str) -> &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 result;
1515+ {
1616+ let string2 = String::from("xyz");
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 {
55+ author: &str,
66+ title: &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)
+23
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+ #[test]
1818+ fn you_can_assert() {
1919+ // TODO: Test the function `is_even` with some values.
2020+ assert!();
2121+ assert!();
2222+ }
2323+}
+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!();
1919+ assert_eq!();
2020+ assert_eq!();
2121+ assert_eq!();
2222+ }
2323+}
+49
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!(todo!(), 10); // Check width
3333+ assert_eq!(todo!(), 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+ fn negative_width() {
4040+ let _rect = Rectangle::new(-10, 10);
4141+ }
4242+4343+ // TODO: This test should check if the program panics when we try to create
4444+ // a rectangle with negative height.
4545+ #[test]
4646+ fn negative_height() {
4747+ let _rect = Rectangle::new(10, -10);
4848+ }
4949+}
+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 = todo!();
1717+1818+ assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
1919+ assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
2020+ assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
2121+ assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
2222+ assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
2323+ assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
2424+ }
2525+}
+57
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) => todo!(),
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+}
2020+2121+// TODO: Apply the `capitalize_first` function again to a slice of string
2222+// slices. Return a single string.
2323+// ["hello", " ", "world"] -> "Hello World"
2424+fn capitalize_words_string(words: &[&str]) -> String {
2525+ // ???
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_success() {
3838+ assert_eq!(capitalize_first("hello"), "Hello");
3939+ }
4040+4141+ #[test]
4242+ fn test_empty() {
4343+ assert_eq!(capitalize_first(""), "");
4444+ }
4545+4646+ #[test]
4747+ fn test_iterate_string_vec() {
4848+ let words = vec!["hello", "world"];
4949+ assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
5050+ }
5151+5252+ #[test]
5353+ fn test_iterate_into_string() {
5454+ let words = vec!["hello", " ", "world"];
5555+ assert_eq!(capitalize_words_string(&words), "Hello World");
5656+ }
5757+}
+73
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+ todo!();
1515+}
1616+1717+// TODO: Add the correct return type and complete the function body.
1818+// Desired output: `Ok([1, 11, 1426, 3])`
1919+fn result_with_list() {
2020+ let numbers = [27, 297, 38502, 81];
2121+ let division_results = numbers.into_iter().map(|n| divide(n, 27));
2222+}
2323+2424+// TODO: Add the correct return type and complete the function body.
2525+// Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]`
2626+fn list_of_results() {
2727+ let numbers = [27, 297, 38502, 81];
2828+ let division_results = numbers.into_iter().map(|n| divide(n, 27));
2929+}
3030+3131+fn main() {
3232+ // You can optionally experiment here.
3333+}
3434+3535+#[cfg(test)]
3636+mod tests {
3737+ use super::*;
3838+3939+ #[test]
4040+ fn test_success() {
4141+ assert_eq!(divide(81, 9), Ok(9));
4242+ }
4343+4444+ #[test]
4545+ fn test_divide_by_0() {
4646+ assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
4747+ }
4848+4949+ #[test]
5050+ fn test_integer_overflow() {
5151+ assert_eq!(divide(i64::MIN, -1), Err(DivisionError::IntegerOverflow));
5252+ }
5353+5454+ #[test]
5555+ fn test_not_divisible() {
5656+ assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));
5757+ }
5858+5959+ #[test]
6060+ fn test_divide_0_by_something() {
6161+ assert_eq!(divide(0, 81), Ok(0));
6262+ }
6363+6464+ #[test]
6565+ fn test_result_with_list() {
6666+ assert_eq!(result_with_list().unwrap(), [1, 11, 1426, 3]);
6767+ }
6868+6969+ #[test]
7070+ fn test_list_of_results() {
7171+ assert_eq!(list_of_results(), [Ok(1), Ok(11), Ok(1426), Ok(3)]);
7272+ }
7373+}
+41
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+}
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 factorial_of_0() {
2525+ assert_eq!(factorial(0), 1);
2626+ }
2727+2828+ #[test]
2929+ fn factorial_of_1() {
3030+ assert_eq!(factorial(1), 1);
3131+ }
3232+ #[test]
3333+ fn factorial_of_2() {
3434+ assert_eq!(factorial(2), 2);
3535+ }
3636+3737+ #[test]
3838+ fn factorial_of_4() {
3939+ assert_eq!(factorial(4), 24);
4040+ }
4141+}
+153
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+}
3232+3333+fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
3434+ let mut count = 0;
3535+ for map in collection {
3636+ for val in map.values() {
3737+ if *val == value {
3838+ count += 1;
3939+ }
4040+ }
4141+ }
4242+ count
4343+}
4444+4545+// TODO: Implement the functionality of `count_collection_for` but with an
4646+// iterator instead of a `for` loop.
4747+fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
4848+ // `collection` is a slice of hash maps.
4949+ // collection = [{ "variables1": Complete, "from_str": None, … },
5050+ // { "variables2": Complete, … }, … ]
5151+}
5252+5353+fn main() {
5454+ // You can optionally experiment here.
5555+}
5656+5757+#[cfg(test)]
5858+mod tests {
5959+ use super::*;
6060+6161+ fn get_map() -> HashMap<String, Progress> {
6262+ use Progress::*;
6363+6464+ let mut map = HashMap::new();
6565+ map.insert(String::from("variables1"), Complete);
6666+ map.insert(String::from("functions1"), Complete);
6767+ map.insert(String::from("hashmap1"), Complete);
6868+ map.insert(String::from("arc1"), Some);
6969+ map.insert(String::from("as_ref_mut"), None);
7070+ map.insert(String::from("from_str"), None);
7171+7272+ map
7373+ }
7474+7575+ fn get_vec_map() -> Vec<HashMap<String, Progress>> {
7676+ use Progress::*;
7777+7878+ let map = get_map();
7979+8080+ let mut other = HashMap::new();
8181+ other.insert(String::from("variables2"), Complete);
8282+ other.insert(String::from("functions2"), Complete);
8383+ other.insert(String::from("if1"), Complete);
8484+ other.insert(String::from("from_into"), None);
8585+ other.insert(String::from("try_from_into"), None);
8686+8787+ vec![map, other]
8888+ }
8989+9090+ #[test]
9191+ fn count_complete() {
9292+ let map = get_map();
9393+ assert_eq!(count_iterator(&map, Progress::Complete), 3);
9494+ }
9595+9696+ #[test]
9797+ fn count_some() {
9898+ let map = get_map();
9999+ assert_eq!(count_iterator(&map, Progress::Some), 1);
100100+ }
101101+102102+ #[test]
103103+ fn count_none() {
104104+ let map = get_map();
105105+ assert_eq!(count_iterator(&map, Progress::None), 2);
106106+ }
107107+108108+ #[test]
109109+ fn count_complete_equals_for() {
110110+ let map = get_map();
111111+ let progress_states = [Progress::Complete, Progress::Some, Progress::None];
112112+ for progress_state in progress_states {
113113+ assert_eq!(
114114+ count_for(&map, progress_state),
115115+ count_iterator(&map, progress_state),
116116+ );
117117+ }
118118+ }
119119+120120+ #[test]
121121+ fn count_collection_complete() {
122122+ let collection = get_vec_map();
123123+ assert_eq!(
124124+ count_collection_iterator(&collection, Progress::Complete),
125125+ 6,
126126+ );
127127+ }
128128+129129+ #[test]
130130+ fn count_collection_some() {
131131+ let collection = get_vec_map();
132132+ assert_eq!(count_collection_iterator(&collection, Progress::Some), 1);
133133+ }
134134+135135+ #[test]
136136+ fn count_collection_none() {
137137+ let collection = get_vec_map();
138138+ assert_eq!(count_collection_iterator(&collection, Progress::None), 4);
139139+ }
140140+141141+ #[test]
142142+ fn count_collection_equals_for() {
143143+ let collection = get_vec_map();
144144+ let progress_states = [Progress::Complete, Progress::Some, Progress::None];
145145+146146+ for progress_state in progress_states {
147147+ assert_eq!(
148148+ count_collection_for(&collection, progress_state),
149149+ count_collection_iterator(&collection, progress_state),
150150+ );
151151+ }
152152+ }
153153+}
+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)
+45
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+2828+ let mut join_handles = Vec::new();
2929+3030+ for offset in 0..8 {
3131+ // TODO: Define `child_numbers` using `shared_numbers`.
3232+ // let child_numbers = ???;
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+}
+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, List),
1616+ Nil,
1717+}
1818+1919+// TODO: Create an empty cons list.
2020+fn create_empty_list() -> List {
2121+ todo!()
2222+}
2323+2424+// TODO: Create a non-empty cons list.
2525+fn create_non_empty_list() -> List {
2626+ todo!()
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, todo!()));
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, todo!()));
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, todo!()));
6868+ }
6969+}
+105
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::new(Sun));
6464+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
6565+ saturn.details();
6666+6767+ // TODO
6868+ let uranus = Planet::Uranus(Rc::new(Sun));
6969+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
7070+ uranus.details();
7171+7272+ // TODO
7373+ let neptune = Planet::Neptune(Rc::new(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+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
9696+9797+ // TODO
9898+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
9999+100100+ // TODO
101101+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
102102+103103+ assert_eq!(Rc::strong_count(&sun), 1);
104104+ }
105105+}
+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)
+37
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+ }
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+}
+34
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, 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(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+ });
2424+ handles.push(handle);
2525+ }
2626+2727+ // Waiting for all jobs to complete.
2828+ for handle in handles {
2929+ handle.join().unwrap();
3030+ }
3131+3232+ // TODO: Print the value of `JobStatus.jobs_done`.
3333+ println!("Jobs done: {}", todo!());
3434+}
+60
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+ thread::spawn(move || {
2121+ for val in q.first_half {
2222+ println!("Sending {val:?}");
2323+ tx.send(val).unwrap();
2424+ thread::sleep(Duration::from_millis(250));
2525+ }
2626+ });
2727+2828+ thread::spawn(move || {
2929+ for val in q.second_half {
3030+ println!("Sending {val:?}");
3131+ tx.send(val).unwrap();
3232+ thread::sleep(Duration::from_millis(250));
3333+ }
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+ #[test]
4646+ fn threads3() {
4747+ let (tx, rx) = mpsc::channel();
4848+ let queue = Queue::new();
4949+5050+ send_tx(queue, tx);
5151+5252+ let mut received = Vec::with_capacity(10);
5353+ for value in rx {
5454+ received.push(value);
5555+ }
5656+5757+ received.sort();
5858+ assert_eq!(received, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
5959+ }
6060+}
+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+fn main() {
22+ my_macro!();
33+}
44+55+// TODO: Fix the compiler error by moving the whole definition of this macro.
66+macro_rules! my_macro {
77+ () => {
88+ println!("Check out my macro!");
99+ };
1010+}
+13
exercises/21_macros/macros3.rs
···11+// TODO: Fix the compiler error without taking the macro definition out of this
22+// module.
33+mod macros {
44+ macro_rules! my_macro {
55+ () => {
66+ println!("Check out my macro!");
77+ };
88+ }
99+}
1010+1111+fn main() {
1212+ my_macro!();
1313+}
+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 = 3.14;
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+ for x in option {
66+ res += x;
77+ }
88+99+ println!("{res}");
1010+}
+27
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 my_option.is_none() {
99+ println!("{:?}", my_option.unwrap());
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 my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
1919+ println!("This Vec is empty, see? {my_empty_vec:?}");
2020+2121+ let mut value_a = 45;
2222+ let mut value_b = 66;
2323+ // Let's swap these two!
2424+ value_a = value_b;
2525+ value_b = value_a;
2626+ println!("value a: {value_a}; value b: {value_b}");
2727+}
+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)
+62
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>(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>(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>(arg: &mut T) {
2121+ // TODO: Implement the function body.
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 different_counts() {
3434+ let s = "Café au lait";
3535+ assert_ne!(char_counter(s), byte_counter(s));
3636+ }
3737+3838+ #[test]
3939+ fn same_counts() {
4040+ let s = "Cafe au lait";
4141+ assert_eq!(char_counter(s), byte_counter(s));
4242+ }
4343+4444+ #[test]
4545+ fn different_counts_using_string() {
4646+ let s = String::from("Café au lait");
4747+ assert_ne!(char_counter(s.clone()), byte_counter(s));
4848+ }
4949+5050+ #[test]
5151+ fn same_counts_using_string() {
5252+ let s = String::from("Cafe au lait");
5353+ assert_eq!(char_counter(s.clone()), byte_counter(s));
5454+ }
5555+5656+ #[test]
5757+ fn mut_box() {
5858+ let mut num: Box<u32> = Box::new(3);
5959+ num_sq(&mut num);
6060+ assert_eq!(*num, 9);
6161+ }
6262+}
+130
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+}
3939+4040+fn main() {
4141+ // Use the `from` function.
4242+ let p1 = Person::from("Mark,20");
4343+ println!("{p1:?}");
4444+4545+ // Since `From` is implemented for Person, we are able to use `Into`.
4646+ let p2: Person = "Gerald,70".into();
4747+ println!("{p2:?}");
4848+}
4949+5050+#[cfg(test)]
5151+mod tests {
5252+ use super::*;
5353+5454+ #[test]
5555+ fn test_default() {
5656+ let dp = Person::default();
5757+ assert_eq!(dp.name, "John");
5858+ assert_eq!(dp.age, 30);
5959+ }
6060+6161+ #[test]
6262+ fn test_bad_convert() {
6363+ let p = Person::from("");
6464+ assert_eq!(p.name, "John");
6565+ assert_eq!(p.age, 30);
6666+ }
6767+6868+ #[test]
6969+ fn test_good_convert() {
7070+ let p = Person::from("Mark,20");
7171+ assert_eq!(p.name, "Mark");
7272+ assert_eq!(p.age, 20);
7373+ }
7474+7575+ #[test]
7676+ fn test_bad_age() {
7777+ let p = Person::from("Mark,twenty");
7878+ assert_eq!(p.name, "John");
7979+ assert_eq!(p.age, 30);
8080+ }
8181+8282+ #[test]
8383+ fn test_missing_comma_and_age() {
8484+ let p: Person = Person::from("Mark");
8585+ assert_eq!(p.name, "John");
8686+ assert_eq!(p.age, 30);
8787+ }
8888+8989+ #[test]
9090+ fn test_missing_age() {
9191+ let p: Person = Person::from("Mark,");
9292+ assert_eq!(p.name, "John");
9393+ assert_eq!(p.age, 30);
9494+ }
9595+9696+ #[test]
9797+ fn test_missing_name() {
9898+ let p: Person = Person::from(",1");
9999+ assert_eq!(p.name, "John");
100100+ assert_eq!(p.age, 30);
101101+ }
102102+103103+ #[test]
104104+ fn test_missing_name_and_age() {
105105+ let p: Person = Person::from(",");
106106+ assert_eq!(p.name, "John");
107107+ assert_eq!(p.age, 30);
108108+ }
109109+110110+ #[test]
111111+ fn test_missing_name_and_invalid_age() {
112112+ let p: Person = Person::from(",one");
113113+ assert_eq!(p.name, "John");
114114+ assert_eq!(p.age, 30);
115115+ }
116116+117117+ #[test]
118118+ fn test_trailing_comma() {
119119+ let p: Person = Person::from("Mike,32,");
120120+ assert_eq!(p.name, "John");
121121+ assert_eq!(p.age, 30);
122122+ }
123123+124124+ #[test]
125125+ fn test_trailing_comma_and_some_string() {
126126+ let p: Person = Person::from("Mike,32,dog");
127127+ assert_eq!(p.name, "John");
128128+ assert_eq!(p.age, 30);
129129+ }
130130+}
+113
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+}
4646+4747+fn main() {
4848+ let p = "Mark,20".parse::<Person>();
4949+ println!("{p:?}");
5050+}
5151+5252+#[cfg(test)]
5353+mod tests {
5454+ use super::*;
5555+ use ParsePersonError::*;
5656+5757+ #[test]
5858+ fn empty_input() {
5959+ assert_eq!("".parse::<Person>(), Err(BadLen));
6060+ }
6161+6262+ #[test]
6363+ fn good_input() {
6464+ let p = "John,32".parse::<Person>();
6565+ assert!(p.is_ok());
6666+ let p = p.unwrap();
6767+ assert_eq!(p.name, "John");
6868+ assert_eq!(p.age, 32);
6969+ }
7070+7171+ #[test]
7272+ fn missing_age() {
7373+ assert!(matches!("John,".parse::<Person>(), Err(ParseInt(_))));
7474+ }
7575+7676+ #[test]
7777+ fn invalid_age() {
7878+ assert!(matches!("John,twenty".parse::<Person>(), Err(ParseInt(_))));
7979+ }
8080+8181+ #[test]
8282+ fn missing_comma_and_age() {
8383+ assert_eq!("John".parse::<Person>(), Err(BadLen));
8484+ }
8585+8686+ #[test]
8787+ fn missing_name() {
8888+ assert_eq!(",1".parse::<Person>(), Err(NoName));
8989+ }
9090+9191+ #[test]
9292+ fn missing_name_and_age() {
9393+ assert!(matches!(",".parse::<Person>(), Err(NoName | ParseInt(_))));
9494+ }
9595+9696+ #[test]
9797+ fn missing_name_and_invalid_age() {
9898+ assert!(matches!(
9999+ ",one".parse::<Person>(),
100100+ Err(NoName | ParseInt(_)),
101101+ ));
102102+ }
103103+104104+ #[test]
105105+ fn trailing_comma() {
106106+ assert_eq!("John,32,".parse::<Person>(), Err(BadLen));
107107+ }
108108+109109+ #[test]
110110+ fn trailing_comma_and_some_string() {
111111+ assert_eq!("John,32,man".parse::<Person>(), Err(BadLen));
112112+ }
113113+}
+177
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+}
3333+3434+// TODO: Array implementation.
3535+impl TryFrom<[i16; 3]> for Color {
3636+ type Error = IntoColorError;
3737+3838+ fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}
3939+}
4040+4141+// TODO: Slice implementation.
4242+// This implementation needs to check the slice length.
4343+impl TryFrom<&[i16]> for Color {
4444+ type Error = IntoColorError;
4545+4646+ fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}
4747+}
4848+4949+fn main() {
5050+ // Using the `try_from` function.
5151+ let c1 = Color::try_from((183, 65, 14));
5252+ println!("{c1:?}");
5353+5454+ // Since `TryFrom` is implemented for `Color`, we can use `TryInto`.
5555+ let c2: Result<Color, _> = [183, 65, 14].try_into();
5656+ println!("{c2:?}");
5757+5858+ let v = vec![183, 65, 14];
5959+ // With slice we should use the `try_from` function
6060+ let c3 = Color::try_from(&v[..]);
6161+ println!("{c3:?}");
6262+ // or put the slice within round brackets and use `try_into`.
6363+ let c4: Result<Color, _> = (&v[..]).try_into();
6464+ println!("{c4:?}");
6565+}
6666+6767+#[cfg(test)]
6868+mod tests {
6969+ use super::*;
7070+ use IntoColorError::*;
7171+7272+ #[test]
7373+ fn test_tuple_out_of_range_positive() {
7474+ assert_eq!(Color::try_from((256, 1000, 10000)), Err(IntConversion));
7575+ }
7676+7777+ #[test]
7878+ fn test_tuple_out_of_range_negative() {
7979+ assert_eq!(Color::try_from((-1, -10, -256)), Err(IntConversion));
8080+ }
8181+8282+ #[test]
8383+ fn test_tuple_sum() {
8484+ assert_eq!(Color::try_from((-1, 255, 255)), Err(IntConversion));
8585+ }
8686+8787+ #[test]
8888+ fn test_tuple_correct() {
8989+ let c: Result<Color, _> = (183, 65, 14).try_into();
9090+ assert!(c.is_ok());
9191+ assert_eq!(
9292+ c.unwrap(),
9393+ Color {
9494+ red: 183,
9595+ green: 65,
9696+ blue: 14,
9797+ }
9898+ );
9999+ }
100100+101101+ #[test]
102102+ fn test_array_out_of_range_positive() {
103103+ let c: Result<Color, _> = [1000, 10000, 256].try_into();
104104+ assert_eq!(c, Err(IntConversion));
105105+ }
106106+107107+ #[test]
108108+ fn test_array_out_of_range_negative() {
109109+ let c: Result<Color, _> = [-10, -256, -1].try_into();
110110+ assert_eq!(c, Err(IntConversion));
111111+ }
112112+113113+ #[test]
114114+ fn test_array_sum() {
115115+ let c: Result<Color, _> = [-1, 255, 255].try_into();
116116+ assert_eq!(c, Err(IntConversion));
117117+ }
118118+119119+ #[test]
120120+ fn test_array_correct() {
121121+ let c: Result<Color, _> = [183, 65, 14].try_into();
122122+ assert!(c.is_ok());
123123+ assert_eq!(
124124+ c.unwrap(),
125125+ Color {
126126+ red: 183,
127127+ green: 65,
128128+ blue: 14
129129+ }
130130+ );
131131+ }
132132+133133+ #[test]
134134+ fn test_slice_out_of_range_positive() {
135135+ let arr = [10000, 256, 1000];
136136+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
137137+ }
138138+139139+ #[test]
140140+ fn test_slice_out_of_range_negative() {
141141+ let arr = [-256, -1, -10];
142142+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
143143+ }
144144+145145+ #[test]
146146+ fn test_slice_sum() {
147147+ let arr = [-1, 255, 255];
148148+ assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
149149+ }
150150+151151+ #[test]
152152+ fn test_slice_correct() {
153153+ let v = vec![183, 65, 14];
154154+ let c: Result<Color, _> = Color::try_from(&v[..]);
155155+ assert!(c.is_ok());
156156+ assert_eq!(
157157+ c.unwrap(),
158158+ Color {
159159+ red: 183,
160160+ green: 65,
161161+ blue: 14,
162162+ }
163163+ );
164164+ }
165165+166166+ #[test]
167167+ fn test_slice_excess_length() {
168168+ let v = vec![0, 0, 0, 0];
169169+ assert_eq!(Color::try_from(&v[..]), Err(BadLen));
170170+ }
171171+172172+ #[test]
173173+ fn test_slice_insufficient_length() {
174174+ let v = vec![0, 0];
175175+ assert_eq!(Color::try_from(&v[..]), Err(BadLen));
176176+ }
177177+}
+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()
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.
+31
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 main() {
1616+ // You can optionally experiment here.
1717+}
1818+1919+// Don't change the tests!
2020+#[cfg(test)]
2121+mod tests {
2222+ use super::*;
2323+2424+ #[test]
2525+ fn verify_test() {
2626+ assert_eq!(calculate_price_of_apples(35), 70);
2727+ assert_eq!(calculate_price_of_apples(40), 80);
2828+ assert_eq!(calculate_price_of_apples(41), 41);
2929+ assert_eq!(calculate_price_of_apples(65), 65);
3030+ }
3131+}
+63
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+}
3232+3333+fn main() {
3434+ // You can optionally experiment here.
3535+}
3636+3737+#[cfg(test)]
3838+mod tests {
3939+ // TODO: What do we need to import to have `transformer` in scope?
4040+ // use ???;
4141+ use super::Command;
4242+4343+ #[test]
4444+ fn it_works() {
4545+ let input = vec![
4646+ ("hello".to_string(), Command::Uppercase),
4747+ (" all roads lead to rome! ".to_string(), Command::Trim),
4848+ ("foo".to_string(), Command::Append(1)),
4949+ ("bar".to_string(), Command::Append(5)),
5050+ ];
5151+ let output = transformer(input);
5252+5353+ assert_eq!(
5454+ output,
5555+ [
5656+ "HELLO",
5757+ "all roads lead to rome!",
5858+ "foobar",
5959+ "barbarbarbarbarbar",
6060+ ]
6161+ );
6262+ }
6363+}
+64
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+1414+// TODO: Adjust the struct as described above.
1515+struct ReportCard {
1616+ grade: f32,
1717+ student_name: String,
1818+ student_age: u8,
1919+}
2020+2121+// TODO: Adjust the impl block as described above.
2222+impl ReportCard {
2323+ fn print(&self) -> String {
2424+ format!(
2525+ "{} ({}) - achieved a grade of {}",
2626+ &self.student_name, &self.student_age, &self.grade,
2727+ )
2828+ }
2929+}
3030+3131+fn main() {
3232+ // You can optionally experiment here.
3333+}
3434+3535+#[cfg(test)]
3636+mod tests {
3737+ use super::*;
3838+3939+ #[test]
4040+ fn generate_numeric_report_card() {
4141+ let report_card = ReportCard {
4242+ grade: 2.1,
4343+ student_name: "Tom Wriggle".to_string(),
4444+ student_age: 12,
4545+ };
4646+ assert_eq!(
4747+ report_card.print(),
4848+ "Tom Wriggle (12) - achieved a grade of 2.1",
4949+ );
5050+ }
5151+5252+ #[test]
5353+ fn generate_alphabetic_report_card() {
5454+ let report_card = ReportCard {
5555+ grade: "A+",
5656+ student_name: "Gary Plotter".to_string(),
5757+ student_age: 11,
5858+ };
5959+ assert_eq!(
6060+ report_card.print(),
6161+ "Gary Plotter (11) - achieved a grade of A+",
6262+ );
6363+ }
6464+}
···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+}
+4
solutions/00_intro/intro2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/01_variables/variables1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/01_variables/variables2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/01_variables/variables3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/01_variables/variables4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/01_variables/variables5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/01_variables/variables6.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/02_functions/functions1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/02_functions/functions2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/02_functions/functions3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/02_functions/functions4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/02_functions/functions5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/03_if/if1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/03_if/if2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/03_if/if3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/04_primitive_types/primitive_types1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/04_primitive_types/primitive_types2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/04_primitive_types/primitive_types3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/04_primitive_types/primitive_types4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/04_primitive_types/primitive_types5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/04_primitive_types/primitive_types6.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/05_vecs/vecs1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/05_vecs/vecs2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/06_move_semantics/move_semantics1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/06_move_semantics/move_semantics2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/06_move_semantics/move_semantics3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/06_move_semantics/move_semantics4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/06_move_semantics/move_semantics5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/07_structs/structs1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/07_structs/structs2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/07_structs/structs3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/08_enums/enums1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/08_enums/enums2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/08_enums/enums3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/09_strings/strings1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/09_strings/strings2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/09_strings/strings3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/09_strings/strings4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/10_modules/modules1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/10_modules/modules2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/10_modules/modules3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/11_hashmaps/hashmaps1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/11_hashmaps/hashmaps2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/11_hashmaps/hashmaps3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/12_options/options1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/12_options/options2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/12_options/options3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/13_error_handling/errors1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/13_error_handling/errors2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/13_error_handling/errors3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/13_error_handling/errors4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/13_error_handling/errors5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/13_error_handling/errors6.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/14_generics/generics1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/14_generics/generics2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/15_traits/traits1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/15_traits/traits2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/15_traits/traits3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/15_traits/traits4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/15_traits/traits5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/16_lifetimes/lifetimes1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/16_lifetimes/lifetimes2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/16_lifetimes/lifetimes3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/17_tests/tests1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/17_tests/tests2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/17_tests/tests3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/18_iterators/iterators1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/18_iterators/iterators2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/18_iterators/iterators3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/18_iterators/iterators4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/18_iterators/iterators5.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/19_smart_pointers/arc1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/19_smart_pointers/box1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/19_smart_pointers/cow1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/19_smart_pointers/rc1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/20_threads/threads1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/20_threads/threads2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/20_threads/threads3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/21_macros/macros1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/21_macros/macros2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/21_macros/macros3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/21_macros/macros4.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/22_clippy/clippy1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/22_clippy/clippy2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/22_clippy/clippy3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/23_conversions/as_ref_mut.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/23_conversions/from_into.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/23_conversions/from_str.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/23_conversions/try_from_into.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/23_conversions/using_as.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+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.
+4
solutions/quizzes/quiz1.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/quizzes/quiz2.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}
+4
solutions/quizzes/quiz3.rs
···11+fn main() {
22+ // DON'T EDIT THIS SOLUTION FILE!
33+ // It will be automatically filled after you finish the exercise.
44+}