+++ title = "Rustlings - Solutions" date = 2024-02-10 [taxonomies] tags = ["rust", "learning"] +++ [Rustlings](https://github.com/rust-lang/rustlings/tree/main) is a nice project presenting you with a serie of small exercises to learn most of the concept of the languages. From declaring variables to more advances concepts. We are presented with a failing program and should fix it in order to compile. Below are my solutions, maybe it'll help someone, possibly future me who knows. [intro2.rs](#intro2-rs) [variables1.rs](#variables-variables1-rs) [variables2.rs](#variables-variables2-rs) [variables3.rs](#variables-variables3-rs) [variables4.rs](#variables-variables4-rs) [variables5.rs](#variables-variables5-rs) [variables6.rs](#variables-variables6-rs) [functions1.rs](#functions-functions1-rs) [functions2.rs](#functions-functions2-rs) [functions3.rs](#functions-functions3-rs) [functions4.rs](#functions-functions4-rs) [functions5.rs](#functions-functions5-rs) [if1.rs](#if-if1-rs) [if2.rs](#if-if2-rs) [if3.rs](#if-if3-rs) [quiz1.rs](#quiz1-rs) [primitive_types1.rs](#primitive-types-primitive-types-1-rs) [primitive_types2.rs](#primitive-types-primitive-types-2-rs) [primitive_types3.rs](#primitive-types-primitive-types-3-rs) [primitive_types4.rs](#primitive-types-primitive-types-4-rs) [primitive_types5.rs](#primitive-types-primitive-types-5-rs) [primitive_types6.rs](#primitive-types-primitive-types-6-rs) [vecs1.rs](#vecs-vecs1-rs) [vecs2.rs](#vecs-vecs2-rs) [move_semantics1.rs](#move-semantics-move-semantics1-rs) [move_semantics2.rs](#move-semantics-move-semantics2-rs) [move_semantics3.rs](#move-semantics-move-semantics3-rs) [move_semantics4.rs](#move-semantics-move-semantics4-rs) [move_semantics5.rs](#move-semantics-move-semantics5-rs) [move_semantics6.rs](#move-semantics-move-semantics6-rs) [structs1.rs](#structs-structs1-rs) [structs2.rs](#structs-structs2-rs) [structs3.rs](#structs-structs3-rs) [enums1.rs](#enums-enums1-rs) [enums2.rs](#enums-enums2-rs) [enums3.rs](#enums-enums3-rs) [strings1.rs](#strings-strings1-rs) [strings2.rs](#strings-strings2-rs) [strings3.rs](#strings-strings3-rs) [strings4.rs](#strings-strings4-rs) [modules1.rs](#modules-modules1-rs) [modules2.rs](#modules-modules2-rs) [modules3.rs](#modules-modules3-rs) [hashmaps1.rs](#hashmaps-hashmaps1-rs) [hashmaps2.rs](#hashmaps-hashmaps2-rs) [hashmaps3.rs](#hashmaps-hashmaps3-rs) [quiz2.rs](#quiz2-rs) [options1.rs](#options-options1-rs) [options2.rs](#options-options2-rs) [options3.rs](#options-options3-rs) [errors1.rs](#error-handling-errors1-rs) [errors2.rs](#error-handling-errors2-rs) [errors3.rs](#error-handling-errors3-rs) [errors4.rs](#error-handling-errors4-rs) [errors5.rs](#error-handling-errors5-rs) [errors6.rs](#error-handling-errors6-rs) [generics1](#generics-generics1-rs) [generics2](#generics-generics2-rs) TBC. ### intro2.rs Needed to add an argument to the `println` macro. Or remove the expected argument I guess. ```rs // Make the code print a greeting to the world. fn main() { println!("Hello {}!", "world"); } ``` ### variables/variables1.rs We need to define `x` using `let`. ```rs // Make me compile fn main() { let x = 5; println!("x has the value {}", x); } ``` ### variables/variables2.rs `x` was not initialized. You can change leave the default type like I did or specify whatever you want (as long as it's comparable to `10`). ```rs fn main() { let x = 0; if x == 10 { println!("x is ten!"); } else { println!("x is not ten!"); } } ``` ### variables/variables3.rs `x` needs to be assigned a value before being used. ```rs fn main() { let x: i32 = 12; println!("Number {}", x); } ``` ### variables/variables4.rs Variables are immutable by default, here we want to change the value so we need to initialize the variable as mutable. ```rs fn main() { let mut x = 3; println!("Number {}", x); x = 5; // don't change this line println!("Number {}", x); } ``` ### variables/variables5.rs Here we "shadow" `x` by re-declaring another variable with the same name. ```rs fn main() { let number = "T-H-R-E-E"; // don't change this line println!("Spell a Number : {}", number); let number = 3; println!("Number plus two is : {}", number + 2); } ``` ### variables/variables6.rs A `const` need to be typed. ```rs const NUMBER: usize = 3; fn main() { println!("Number {}", NUMBER); } ``` ### functions/functions1.rs We need to define the function `call_me` with no arguments and nothing returned. ```rs fn main() { call_me(); } fn call_me() { println!("Call me!"); } ``` ### functions/functions2.rs We need to type the function's argument `num`. Could be any number types. ```rs fn main() { call_me(3); } fn call_me(num: i32) { for i in 0..num { println!("Ring! Call number {}", i + 1); } } ``` ### functions/functions3.rs This one is the kind of the reverse, we cannot call a function without passing the expected arguments. ```rs fn main() { call_me(4); } fn call_me(num: u32) { for i in 0..num { println!("Ring! Call number {}", i + 1); } } ``` ### functions/functions4.rs Here we are missing the return type of `sale_price`. Have to be the same as the argument given because we are returning either `price - 10` or `price - 3` which would be the same type as `price`. ```rs // This store is having a sale where if the price is an even number, you get 10 // Rustbucks off, but if it's an odd number, it's 3 Rustbucks off. (Don't worry // about the function bodies themselves, we're only interested in the signatures // for now. If anything, this is a good way to peek ahead to future exercises!) fn main() { let original_price = 51; println!("Your sale price is {}", sale_price(original_price)); } fn sale_price(price: i32) -> i32 { if is_even(price) { price - 10 } else { price - 3 } } fn is_even(num: i32) -> bool { num % 2 == 0 } ``` ### functions/functions5.rs Here they probably want us to remove the `;` and therefore returning the statement. I don't like this syntax so let's just add the `return` keyword like gentlemen. ```rs fn main() { let answer = square(3); println!("The square of 3 is {}", answer); } fn square(num: i32) -> i32 { return num * num; } ``` ### if/if1.rs ```rs pub fn bigger(a: i32, b: i32) -> i32 { // Complete this function to return the bigger number! // Do not use: // - another function call // - additional variables if a > b { return a; } else { return b; } } ``` ### if/if2.rs ```rs // Step 1: Make me compile! // Step 2: Get the bar_for_fuzz and default_to_baz tests passing! // pub fn foo_if_fizz(fizzish: &str) -> &str { if fizzish == "fizz" { return "foo"; } else if fizzish == "fuzz" { return "bar"; } return "baz"; } ``` ### if/if3.rs The `if` statement defining `identifier` was returning different types, which is fine however `identifier` is used below as comparison to integers, therefore we need to ensure that identifier is an `int` all the time. ```rs pub fn animal_habitat(animal: &str) -> &'static str { let identifier = if animal == "crab" { 1 } else if animal == "gopher" { 2 } else if animal == "snake" { 3 } else { 0 }; // DO NOT CHANGE THIS STATEMENT BELOW let habitat = if identifier == 1 { "Beach" } else if identifier == 2 { "Burrow" } else if identifier == 3 { "Desert" } else { "Unknown" }; habitat } ``` ### quiz1.rs ```rs // Mary is buying apples. The price of an apple is calculated as follows: // - An apple costs 2 rustbucks. // - If Mary buys more than 40 apples, each apple only costs 1 rustbuck! // Write a function that calculates the price of an order of apples given the // quantity bought. // // Put your function here! fn calculate_price_of_apples(num: i32) -> i32 { let price_per_apple = if num > 40 { 1 } else { 2 }; return num * price_per_apple; } ``` ### primitive_types/primitive_types_1.rs ```rs // Fill in the rest of the line that has code missing! No hints, there's no // tricks, just get used to typing these :) fn main() { // Booleans (`bool`) let is_morning = true; if is_morning { println!("Good morning!"); } let is_evening = false; if is_evening { println!("Good evening!"); } } ``` ### primitive_types/primitive_types_2.rs ```rs // Fill in the rest of the line that has code missing! No hints, there's no // tricks, just get used to typing these :) fn main() { // Characters (`char`) // Note the _single_ quotes, these are different from the double quotes // you've been seeing around. let my_first_initial = 'C'; if my_first_initial.is_alphabetic() { println!("Alphabetical!"); } else if my_first_initial.is_numeric() { println!("Numerical!"); } else { println!("Neither alphabetic nor numeric!"); } // Finish this line like the example! What's your favorite character? // Try a letter, try a number, try a special character, try a character // from a different language than your own, try an emoji! let your_character = '5'; if your_character.is_alphabetic() { println!("Alphabetical!"); } else if your_character.is_numeric() { println!("Numerical!"); } else { println!("Neither alphabetic nor numeric!"); } } ``` ### primitive_types/primitive_types_3.rs ```rs // Create an array with at least 100 elements in it where the ??? is. // fn main() { let a = ["hello"; 150]; if a.len() >= 100 { println!("Wow, that's a big array!"); } else { println!("Meh, I eat arrays like that for breakfast."); panic!("Array not big enough, more elements needed") } } ``` ### primitive_types/primitive_types_4.rs ```rs // Get a slice out of Array a where the ??? is so that the test passes. #[test] fn slice_out_of_array() { let a = [1, 2, 3, 4, 5]; let nice_slice = &a[1..4]; assert_eq!([2, 3, 4], nice_slice) } ``` ### primitive_types/primitive_types_5.rs Note that you can also destructure it directly when declaring cat, and do: `let (name, age) = ("Furry McFurson", 3.5);`. ```rs // Destructure the `cat` tuple so that the println will work. fn main() { let cat = ("Furry McFurson", 3.5); let (name, age) = cat; println!("{} is {} years old.", name, age); } ``` ### primitive_types/primitive_types_6.rs ```rs // Use a tuple index to access the second element of `numbers`. You can put the // expression for the second element where ??? is so that the test passes. // #[test] fn indexing_tuple() { let numbers = (1, 2, 3); // Replace below ??? with the tuple indexing syntax. let second = numbers.1; assert_eq!(2, second, "This is not the 2nd number in the tuple!") } ``` ### vecs/vecs1.rs ```rs // Your task is to create a `Vec` which holds the exact same elements as in the // array `a`. // // Make me compile and pass the test! fn array_and_vec() -> ([i32; 4], Vec) { let a = [10, 20, 30, 40]; // a plain array let v = Vec::from(a); (a, v) } ``` ### vecs/vecs2.rs ```rs // A Vec of even numbers is given. Your task is to complete the loop so that // each number in the Vec is multiplied by 2. // fn vec_loop(mut v: Vec) -> Vec { for element in v.iter_mut() { // TODO: Fill this up so that each element in the Vec `v` is // multiplied by 2. *element = *element * 2; } // At this point, `v` should be equal to [4, 8, 12, 16, 20]. v } fn vec_map(v: &Vec) -> Vec { v.iter() .map(|element| { // TODO: Do the same thing as above - but instead of mutating the // Vec, you can just return the new number! return element * 2; }) .collect() } ``` ### move_semantics/move_semantics1.rs Cannot push to an immutable `Vec`. Furthermore, as the hint suggest, if we try to access `vec0` in `main` after using `fill_vec`, we get an error indicating that `vec0` was moved to `fill_vec`. ```rs // Execute `rustlings hint move_semantics1` or use the `hint` watch subcommand // for a hint. #[test] fn main() { let vec0 = vec![22, 44, 66]; let vec1 = fill_vec(vec0); assert_eq!(vec1, vec![22, 44, 66, 88]); } fn fill_vec(vec: Vec) -> Vec { let mut vec = vec; vec.push(88); vec } ``` ### move_semantics/move_semantics2.rs We pass a reference to `fill_vec` instead of a value so the ownership does not change, and then `clone` the value to initiate our vector without issue. ```rs // Make the test pass by finding a way to keep both Vecs separate! // #[test] fn main() { let vec0 = vec![22, 44, 66]; let mut vec1 = fill_vec(&vec0); assert_eq!(vec0, vec![22, 44, 66]); assert_eq!(vec1, vec![22, 44, 66, 88]); } fn fill_vec(vec: &Vec) -> Vec { let mut vec = vec.clone(); vec.push(88); vec } ``` ### move_semantics/move_semantics3.rs We've added `mut` in the argument's definition of `fill_vec` to allow us to push into it. ```rs // Make me compile without adding new lines -- just changing existing lines! (no // lines with multiple semicolons necessary!) // #[test] fn main() { let vec0 = vec![22, 44, 66]; let vec1 = fill_vec(vec0); assert_eq!(vec1, vec![22, 44, 66, 88]); } fn fill_vec(mut vec: Vec) -> Vec { vec.push(88); vec } ``` ### move_semantics/move_semantics4.rs Simply move the vector initialization to the `fill_vec` function as asked. ```rs // Refactor this code so that instead of passing `vec0` into the `fill_vec` // function, the Vector gets created in the function itself and passed back to // the main function. // #[test] fn main() { let mut vec1 = fill_vec(); assert_eq!(vec1, vec![22, 44, 66, 88]); } // `fill_vec()` no longer takes `vec: Vec` as argument - don't change this! fn fill_vec() -> Vec { // Instead, let's create and fill the Vec in here - how do you do that? let mut vec = vec![22, 44, 66]; vec.push(88); vec } ``` ### move_semantics/move_semantics5.rs Only one borrow can be active at the same time. In the original order, `y` was unusable once we initialize `z` as it's borrowing the same original value. We need to make sure to finish everything we want to do with `y` before declaring `z`. ```rs // Make me compile only by reordering the lines in `main()`, but without adding, // changing or removing any of them. // #[test] fn main() { let mut x = 100; let y = &mut x; *y += 100; let z = &mut x; *z += 1000; assert_eq!(x, 1200); } ``` ### move_semantics/move_semantics6.rs We had `get_char` take ownership of `data` and `string_uppercase` taking a reference while we need the other way around. ```rs // You can't change anything except adding or removing references. // fn main() { let data = "Rust is great!".to_string(); get_char(&data); string_uppercase(data); } // Should not take ownership fn get_char(data: &String) -> char { data.chars().last().unwrap() } // Should take ownership fn string_uppercase(mut data: String) { data = data.to_uppercase(); println!("{}", data); } ``` ### structs/structs1.rs ```rs // Address all the TODOs to make the tests pass! // struct ColorClassicStruct { red: i32, green: i32, blue: i32, } struct ColorTupleStruct(i32, i32, i32); #[derive(Debug)] struct UnitLikeStruct; #[cfg(test)] mod tests { use super::*; #[test] fn classic_c_structs() { // TODO: Instantiate a classic c struct! let green = ColorClassicStruct { red: 0, green: 255, blue: 0, }; assert_eq!(green.red, 0); assert_eq!(green.green, 255); assert_eq!(green.blue, 0); } #[test] fn tuple_structs() { // TODO: Instantiate a tuple struct! let green = (0, 255, 0); assert_eq!(green.0, 0); assert_eq!(green.1, 255); assert_eq!(green.2, 0); } #[test] fn unit_structs() { // TODO: Instantiate a unit-like struct! let unit_like_struct = UnitLikeStruct; let message = format!("{:?}s are fun!", unit_like_struct); assert_eq!(message, "UnitLikeStructs are fun!"); } } ``` ### structs/structs2.rs ```rs // Address all the TODOs to make the tests pass! // #[derive(Debug)] struct Order { name: String, year: u32, made_by_phone: bool, made_by_mobile: bool, made_by_email: bool, item_number: u32, count: u32, } fn create_order_template() -> Order { Order { name: String::from("Bob"), year: 2019, made_by_phone: false, made_by_mobile: false, made_by_email: true, item_number: 123, count: 0, } } #[cfg(test)] mod tests { use super::*; #[test] fn your_order() { let order_template = create_order_template(); // TODO: Create your own order using the update syntax and template above! let your_order = Order { name: String::from("Hacker in Rust"), count: 1, ..order_template }; assert_eq!(your_order.name, "Hacker in Rust"); assert_eq!(your_order.year, order_template.year); assert_eq!(your_order.made_by_phone, order_template.made_by_phone); assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile); assert_eq!(your_order.made_by_email, order_template.made_by_email); assert_eq!(your_order.item_number, order_template.item_number); assert_eq!(your_order.count, 1); } } ``` ### structs/structs3.rs ```rs // Structs contain data, but can also have logic. In this exercise we have // defined the Package struct and we want to test some logic attached to it. // Make the code compile and the tests pass! // // Execute `rustlings hint structs3` or use the `hint` watch subcommand for a // hint. // I AM NOT DONE #[derive(Debug)] struct Package { sender_country: String, recipient_country: String, weight_in_grams: u32, } impl Package { fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Package { if weight_in_grams < 10 { // This is not how you should handle errors in Rust, // but we will learn about error handling later. panic!("Can not ship a package with weight below 10 grams.") } else { Package { sender_country, recipient_country, weight_in_grams, } } } fn is_international(&self) -> bool { return self.recipient_country != self.sender_country; } fn get_fees(&self, cents_per_gram: u32) -> u32 { return self.weight_in_grams * cents_per_gram; } } ``` ### enums/enums1.rs ```rs #[derive(Debug)] enum Message { Quit, Echo, Move, ChangeColor, } fn main() { println!("{:?}", Message::Quit); println!("{:?}", Message::Echo); println!("{:?}", Message::Move); println!("{:?}", Message::ChangeColor); } ``` ### enums/enums2.rs ```rs #[derive(Debug)] enum Message { // TODO: define the different variants used below Move { x: i32, y: i32 }, Echo(String), ChangeColor(i32, i32, i32), Quit, } impl Message { fn call(&self) { println!("{:?}", self); } } fn main() { let messages = [ Message::Move { x: 10, y: 30 }, Message::Echo(String::from("hello world")), Message::ChangeColor(200, 255, 255), Message::Quit, ]; for message in &messages { message.call(); } } ``` ### enums/enums3.rs Here we need to make sure to use `u8` when defining the `ChangeColor` enum, as in the state implementation that's how color is defined. ```rs enum Message { // TODO Echo(String), ChangeColor(u8, u8, u8), Move(Point), Quit, } struct Point { x: u8, y: u8, } struct State { color: (u8, u8, u8), position: Point, quit: bool, message: String, } impl State { fn change_color(&mut self, color: (u8, u8, u8)) { self.color = color; } fn quit(&mut self) { self.quit = true; } fn echo(&mut self, s: String) { self.message = s } fn move_position(&mut self, p: Point) { self.position = p; } fn process(&mut self, message: Message) { // TODO: create a match expression to process the different message // variants // Remember: When passing a tuple as a function argument, you'll need // extra parentheses: fn function((t, u, p, l, e)) match message { Message::Quit => self.quit = true, Message::ChangeColor(r, g, b) => self.change_color((r, g, b)), Message::Echo(str) => self.echo(str), Message::Move(p) => self.move_position(p), } } } ``` ### strings/strings1.rs ```rs // Make me compile without changing the function signature! // fn main() { let answer = current_favorite_color(); println!("My current favorite color is {}", answer); } fn current_favorite_color() -> String { return String::from("blue"); } ``` ### strings/strings2.rs ```rs // Make me compile without changing the function signature! // fn main() { let word = String::from("green"); // Try not changing this line :) if is_a_color_word(word.as_str()) { println!("That is a color word I know!"); } else { println!("That is not a color word I know."); } } fn is_a_color_word(attempt: &str) -> bool { attempt == "green" || attempt == "blue" || attempt == "red" } ``` ### strings/strings3.rs ```rs fn trim_me(input: &str) -> String { // TODO: Remove whitespace from both ends of a string! return input.trim().to_string(); } fn compose_me(input: &str) -> String { // TODO: Add " world!" to the string! There's multiple ways to do this! return input.to_owned() + " world!"; // return format!("{} world!", input); } fn replace_me(input: &str) -> String { // TODO: Replace "cars" in the string with "balloons"! return input.replace("cars", "balloons"); } ``` ### strings/strings4.rs ```rs // Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your // task is to call one of these two functions on each value depending on what // you think each value is. That is, add either `string_slice` or `string` // before the parentheses on each line. If you're right, it will compile! // fn string_slice(arg: &str) { println!("{}", arg); } fn string(arg: String) { println!("{}", arg); } fn main() { string_slice("blue"); string("red".to_string()); string(String::from("hi")); string("rust is fun!".to_owned()); string_slice("nice weather".into()); string(format!("Interpolation {}", "Station")); string_slice(&String::from("abc")[0..1]); string_slice(" hello there ".trim()); string("Happy Monday!".to_string().replace("Mon", "Tues")); string("mY sHiFt KeY iS sTiCkY".to_lowercase()); } ``` ### modules/modules1.rs Functions in a module are private by default, so here we just need to make `make_sausage` public to be used in the `main` function. ```rs mod sausage_factory { // Don't let anybody outside of this module see this! fn get_secret_recipe() -> String { String::from("Ginger") } pub fn make_sausage() { get_secret_recipe(); println!("sausage!"); } } fn main() { sausage_factory::make_sausage(); } ``` ### modules/modules2.rs We need to two changes here, replace both `???` with the name used in the `main` function (`fruit` and `veggie`). We also need to make those public in order to be able to use it outside of the module. ```rs // You can bring module paths into scopes and provide new names for them with // the 'use' and 'as' keywords. Fix these 'use' statements to make the code // compile. mod delicious_snacks { // TODO: Fix these use statements pub use self::fruits::PEAR as fruit; pub use self::veggies::CUCUMBER as veggie; mod fruits { pub const PEAR: &'static str = "Pear"; pub const APPLE: &'static str = "Apple"; } mod veggies { pub const CUCUMBER: &'static str = "Cucumber"; pub const CARROT: &'static str = "Carrot"; } } fn main() { println!( "favorite snacks: {} and {}", delicious_snacks::fruit, delicious_snacks::veggie ); } ``` ### modules/modules3.rs ```rs // You can use the 'use' keyword to bring module paths from modules from // anywhere and especially from the Rust standard library into your scope. Bring // SystemTime and UNIX_EPOCH from the std::time module. Bonus style points if // you can do it with one line! // // TODO: Complete this use statement use std::time::{SystemTime, UNIX_EPOCH}; fn main() { match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), Err(_) => panic!("SystemTime before UNIX EPOCH!"), } } ``` ### hashmaps/hashmaps1.rs ```rs // A basket of fruits in the form of a hash map needs to be defined. The key // represents the name of the fruit and the value represents how many of that // particular fruit is in the basket. You have to put at least three different // types of fruits (e.g apple, banana, mango) in the basket and the total count // of all the fruits should be at least five. // use std::collections::HashMap; fn fruit_basket() -> HashMap { let mut basket = HashMap::new(); // Two bananas are already given for you :) basket.insert(String::from("banana"), 2); // TODO: Put more fruits in your basket here. basket.insert(String::from("mango"), 6); basket.insert(String::from("apple"), 9); basket } ``` ### hashmaps/hashmaps2.rs Adding `4` of each type of fruit is arbitraty, could be anything, could be randomize, as long as it's more than 11 total as per the requirement. ```rs // We're collecting different fruits to bake a delicious fruit cake. For this, // we have a basket, which we'll represent in the form of a hash map. The key // represents the name of each fruit we collect and the value represents how // many of that particular fruit we have collected. Three types of fruits - // Apple (4), Mango (2) and Lychee (5) are already in the basket hash map. You // must add fruit to the basket so that there is at least one of each kind and // more than 11 in total - we have a lot of mouths to feed. You are not allowed // to insert any more of these fruits! // use std::collections::HashMap; #[derive(Hash, PartialEq, Eq)] enum Fruit { Apple, Banana, Mango, Lychee, Pineapple, } fn fruit_basket(basket: &mut HashMap) { let fruit_kinds = vec![ Fruit::Apple, Fruit::Banana, Fruit::Mango, Fruit::Lychee, Fruit::Pineapple, ]; for fruit in fruit_kinds { // basket. Note that you are not allowed to put any type of fruit that's // already present! if !basket.contains_key(&fruit) { basket.insert(fruit, 4); } } } ``` ### hashmaps/hashmaps3.rs I extracted the logic of updating the score of a team in a separate function, but you could have duplicated it for `team_1` and `team_2` in the `build_scores_table` function directly. ```rs // A list of scores (one per line) of a soccer match is given. Each line is of // the form : ",,," // Example: England,France,4,2 (England scored 4 goals, France 2). // // You have to build a scores table containing the name of the team, goals the // team scored, and goals the team conceded. One approach to build the scores // table is to use a Hashmap. The solution is partially written to use a // Hashmap, complete it to pass the test. use std::collections::HashMap; // A structure to store the goal details of a team. struct Team { goals_scored: u8, goals_conceded: u8, } fn build_scores_table(results: String) -> HashMap { // The name of the team is the key and its associated struct is the value. let mut scores: HashMap = HashMap::new(); for r in results.lines() { let v: Vec<&str> = r.split(',').collect(); let team_1_name = v[0].to_string(); let team_1_score: u8 = v[2].parse().unwrap(); let team_2_name = v[1].to_string(); let team_2_score: u8 = v[3].parse().unwrap(); // TODO: Populate the scores table with details extracted from the // current line. Keep in mind that goals scored by team_1 // will be the number of goals conceded from team_2, and similarly // goals scored by team_2 will be the number of goals conceded by // team_1. add_team_scores( &mut scores, team_1_name.to_string(), team_1_score, team_2_score, ); add_team_scores( &mut scores, team_2_name.to_string(), team_2_score, team_1_score, ); } scores } fn add_team_scores(scores: &mut HashMap, name: String, scored: u8, conceded: u8) { let team = scores.entry(name).or_insert(Team { goals_scored: 0, goals_conceded: 0, }); team.goals_conceded += conceded; team.goals_scored += scored; } ``` ### quiz2.rs ```rs // This is a quiz for the following sections: // - Strings // - Vecs // - Move semantics // - Modules // - Enums // // Let's build a little machine in the form of a function. As input, we're going // to give a list of strings and commands. These commands determine what action // is going to be applied to the string. It can either be: // - Uppercase the string // - Trim the string // - Append "bar" to the string a specified amount of times // The exact form of this will be: // - The input is going to be a Vector of a 2-length tuple, // the first element is the string, the second one is the command. // - The output element is going to be a Vector of strings. pub enum Command { Uppercase, Trim, Append(usize), } mod my_module { use super::Command; // TODO: Complete the function signature! pub fn transformer(input: Vec<(String, Command)>) -> Vec { // TODO: Complete the output declaration! let mut output: Vec = vec![]; for (string, command) in input.iter() { // TODO: Complete the function body. You can do it! match command { Command::Uppercase => { output.push(string.to_uppercase()); } Command::Trim => { output.push(string.trim().to_string()); } Command::Append(n) => { let bars = "bar".repeat(*n); output.push(format!("{}{}", string, bars)); } } } output } } #[cfg(test)] mod tests { // TODO: What do we need to import to have `transformer` in scope? use super::Command; use crate::my_module::transformer; [...] } ``` ### options/options1.rs In the test, I am not sure if they expected `Some` or something else tbh. ```rs // This function returns how much icecream there is left in the fridge. // If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them // all, so there'll be no more left :( fn maybe_icecream(time_of_day: u16) -> Option { // We use the 24-hour system here, so 10PM is a value of 22 and 12AM is a // value of 0 The Option output should gracefully handle cases where // time_of_day > 23. // TODO: Complete the function body - remember to return an Option! if time_of_day > 23 { return None; } if time_of_day < 22 { return Some(5); } return Some(0); } #[cfg(test)] mod tests { use super::*; #[test] fn check_icecream() { assert_eq!(maybe_icecream(9), Some(5)); assert_eq!(maybe_icecream(10), Some(5)); assert_eq!(maybe_icecream(23), Some(0)); assert_eq!(maybe_icecream(22), Some(0)); assert_eq!(maybe_icecream(25), None); } #[test] fn raw_value() { // TODO: Fix this test. How do you get at the value contained in the // Option? let icecreams = maybe_icecream(12); assert_eq!(icecreams, Some(5)); } } ``` ### options/options2.rs ```rs #[cfg(test)] mod tests { #[test] fn simple_option() { let target = "rustlings"; let optional_target = Some(target); // TODO: Make this an if let statement whose value is "Some" type if let Some(word) = optional_target { assert_eq!(word, target); } } #[test] fn layered_option() { let range = 10; let mut optional_integers: Vec> = vec![None]; for i in 1..(range + 1) { optional_integers.push(Some(i)); } let mut cursor = range; // TODO: make this a while let statement - remember that vector.pop also // adds another layer of Option. You can stack `Option`s into // while let and if let. while let Some(Some(integer)) = optional_integers.pop() { assert_eq!(integer, cursor); cursor -= 1; } assert_eq!(cursor, 0); } } ``` ### options/options3.rs ```rs struct Point { x: i32, y: i32, } fn main() { let y: Option = Some(Point { x: 100, y: 200 }); match y { Some(ref p) => println!("Co-ordinates are {},{} ", p.x, p.y), _ => panic!("no match!"), } y; // Fix without deleting this line. } ``` ### error_handling/errors1.rs ```rs // This function refuses to generate text to be printed on a nametag if you pass // it an empty string. It'd be nicer if it explained what the problem was, // instead of just sometimes returning `None`. Thankfully, Rust has a similar // construct to `Option` that can be used to express error conditions. Let's use // it! // pub fn generate_nametag_text(name: String) -> Result { if name.is_empty() { // Empty names aren't allowed. return Err(String::from("`name` was empty; it must be nonempty.")); } else { return Ok(format!("Hi! My name is {}", name)); } } #[cfg(test)] mod tests { use super::*; #[test] fn generates_nametag_text_for_a_nonempty_name() { assert_eq!( generate_nametag_text("Beyoncé".into()), Ok("Hi! My name is Beyoncé".into()) ); } #[test] fn explains_why_generating_nametag_text_fails() { assert_eq!( generate_nametag_text("".into()), // Don't change this line Err("`name` was empty; it must be nonempty.".into()) ); } } ``` ### error_handling/errors2.rs I put both solutions in. The `?` feels good though. ```rs // Say we're writing a game where you can buy items with tokens. All items cost // 5 tokens, and whenever you purchase items there is a processing fee of 1 // token. A player of the game will type in how many items they want to buy, and // the `total_cost` function will calculate the total cost of the tokens. Since // the player typed in the quantity, though, we get it as a string-- and they // might have typed anything, not just numbers! // // Right now, this function isn't handling the error case at all (and isn't // handling the success case properly either). What we want to do is: if we call // the `total_cost` function on a string that is not a number, that function // will return a `ParseIntError`, and in that case, we want to immediately // return that error from our function and not try to multiply and add. // use std::num::ParseIntError; pub fn total_cost(item_quantity: &str) -> Result { let processing_fee = 1; let cost_per_item = 5; let qty = item_quantity.parse::()?; Ok(qty * cost_per_item + processing_fee) // We could do this instead of the ? // let qty = item_quantity.parse::(); // match qty { // Ok(q) => { // return Ok(q * cost_per_item + processing_fee); // } // Err(err) => { // return Err(err); // } // } } ``` ### error_handling/errors3.rs ```rs // This is a program that is trying to use a completed version of the // `total_cost` function from the previous exercise. It's not working though! // Why not? What should we do to fix it? // use std::num::ParseIntError; fn main() -> Result<(), ParseIntError> { let mut tokens = 100; let pretend_user_input = "8"; let cost = total_cost(pretend_user_input)?; if cost > tokens { println!("You can't afford that many!"); } else { tokens -= cost; println!("You now have {} tokens.", tokens); } return Ok(()); } ``` ### error_handling/errors4.rs ```rs #[derive(PartialEq, Debug)] struct PositiveNonzeroInteger(u64); #[derive(PartialEq, Debug)] enum CreationError { Negative, Zero, } impl PositiveNonzeroInteger { fn new(value: i64) -> Result { // Hmm... Why is this always returning an Ok value? if value < 0 { return Err(CreationError::Negative); } if value == 0 { return Err(CreationError::Zero); } return Ok(PositiveNonzeroInteger(value as u64)); } } ``` ### error_handling/errors5.rs ```rs // This exercise uses some concepts that we won't get to until later in the // course, like `Box` and the `From` trait. It's not important to understand // them in detail right now, but you can read ahead if you like. For now, think // of the `Box` type as an "I want anything that does ???" type, which, // given Rust's usual standards for runtime safety, should strike you as // somewhat lenient! // // In short, this particular use case for boxes is for when you want to own a // value and you care only that it is a type which implements a particular // trait. To do so, The Box is declared as of type Box where Trait is // the trait the compiler looks for on any value used in that context. For this // exercise, that context is the potential errors which can be returned in a // Result. // // What can we use to describe both errors? In other words, is there a trait // which both errors implement? // use std::error; use std::fmt; use std::num::ParseIntError; // TODO: update the return type of `main()` to make this compile. fn main() -> Result<(), Box> { let pretend_user_input = "42"; let x: i64 = pretend_user_input.parse()?; println!("output={:?}", PositiveNonzeroInteger::new(x)?); Ok(()) } ``` ### error_handling/errors6.rs ```rs // Using catch-all error types like `Box` isn't recommended // for library code, where callers might want to make decisions based on the // error content, instead of printing it out or propagating it further. Here, we // define a custom error type to make it possible for callers to decide what to // do next when our function returns an error. // use std::num::ParseIntError; // This is a custom error type that we will be using in `parse_pos_nonzero()`. #[derive(PartialEq, Debug)] enum ParsePosNonzeroError { Creation(CreationError), ParseInt(ParseIntError), } impl ParsePosNonzeroError { fn from_creation(err: CreationError) -> ParsePosNonzeroError { return ParsePosNonzeroError::Creation(err); } // TODO: add another error conversion function here. fn from_parseint(err: ParseIntError) -> ParsePosNonzeroError { return ParsePosNonzeroError::ParseInt(err); } } fn parse_pos_nonzero(s: &str) -> Result { // TODO: change this to return an appropriate error instead of panicking // when `parse()` returns an error. match s.parse() { Err(e) => { return Err(ParsePosNonzeroError::from_parseint(e)); } Ok(x) => { return PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation); } } } ``` ### generics/generics1.rs ```rs // This shopping list program isn't compiling! Use your knowledge of generics to // fix it. // fn main() { let mut shopping_list: Vec<&str> = Vec::new(); shopping_list.push("milk"); } ``` ### generics/generics2.rs ```rs // This powerful wrapper provides the ability to store a positive integer value. // Rewrite it using generics so that it supports wrapping ANY type. // struct Wrapper { value: T, } impl Wrapper { pub fn new(value: T) -> Self { Wrapper { value } } } ```