feat: completed solutions

This commit is contained in:
2026-03-23 03:36:33 -04:00
parent 2279bea6f1
commit f568c094cb
65 changed files with 424 additions and 139 deletions
+65 -1
View File
@@ -1,6 +1,6 @@
DON'T EDIT THIS FILE! DON'T EDIT THIS FILE!
structs1 as_ref_mut
intro1 intro1
intro2 intro2
@@ -32,3 +32,67 @@ move_semantics2
move_semantics3 move_semantics3
move_semantics4 move_semantics4
move_semantics5 move_semantics5
structs1
structs2
structs3
enums1
enums2
enums3
strings1
strings2
strings3
strings4
modules1
modules2
modules3
hashmaps1
hashmaps2
hashmaps3
quiz2
options1
options2
options3
errors1
errors2
errors3
errors4
errors5
errors6
generics1
generics2
traits1
traits2
traits3
traits4
traits5
quiz3
lifetimes1
lifetimes2
lifetimes3
tests1
tests2
tests3
iterators1
iterators2
iterators3
iterators4
iterators5
box1
rc1
arc1
cow1
threads1
threads2
threads3
macros1
macros2
macros3
macros4
clippy1
clippy2
clippy3
using_as
from_into
from_str
try_from_into
as_ref_mut
+12 -5
View File
@@ -1,12 +1,15 @@
struct ColorRegularStruct { struct ColorRegularStruct {
// TODO: Add the fields that the test `regular_structs` expects. // TODO: Add the fields that the test `regular_structs` expects.
// What types should the fields have? What are the minimum and maximum values for RGB colors? // What types should the fields have? What are the minimum and maximum values for RGB colors?
red: u8,
green: u8,
blue: u8,
} }
struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */); struct ColorTupleStruct(u8, u8, u8);
#[derive(Debug)] #[derive(Debug)]
struct UnitStruct; struct UnitStruct();
fn main() { fn main() {
// You can optionally experiment here. // You can optionally experiment here.
@@ -19,7 +22,11 @@ mod tests {
#[test] #[test]
fn regular_structs() { fn regular_structs() {
// TODO: Instantiate a regular struct. // TODO: Instantiate a regular struct.
// let green = let green = ColorRegularStruct {
red: 0,
green: 255,
blue: 0,
};
assert_eq!(green.red, 0); assert_eq!(green.red, 0);
assert_eq!(green.green, 255); assert_eq!(green.green, 255);
@@ -29,7 +36,7 @@ mod tests {
#[test] #[test]
fn tuple_structs() { fn tuple_structs() {
// TODO: Instantiate a tuple struct. // TODO: Instantiate a tuple struct.
// let green = let green = ColorTupleStruct(0, 255, 0);
assert_eq!(green.0, 0); assert_eq!(green.0, 0);
assert_eq!(green.1, 255); assert_eq!(green.1, 255);
@@ -39,7 +46,7 @@ mod tests {
#[test] #[test]
fn unit_structs() { fn unit_structs() {
// TODO: Instantiate a unit struct. // TODO: Instantiate a unit struct.
// let unit_struct = let unit_struct = UnitStruct();
let message = format!("{unit_struct:?}s are fun!"); let message = format!("{unit_struct:?}s are fun!");
assert_eq!(message, "UnitStructs are fun!"); assert_eq!(message, "UnitStructs are fun!");
+5 -1
View File
@@ -34,7 +34,11 @@ mod tests {
let order_template = create_order_template(); let order_template = create_order_template();
// TODO: Create your own order using the update syntax and template above! // TODO: Create your own order using the update syntax and template above!
// let your_order = let your_order = Order {
name: "Hacker in Rust".to_string(),
count: 1,
..order_template
};
assert_eq!(your_order.name, "Hacker in Rust"); assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year); assert_eq!(your_order.year, order_template.year);
+4 -2
View File
@@ -24,14 +24,16 @@ impl Package {
} }
// TODO: Add the correct return type to the function signature. // TODO: Add the correct return type to the function signature.
fn is_international(&self) { fn is_international(&self) -> bool {
// TODO: Read the tests that use this method to find out when a package // TODO: Read the tests that use this method to find out when a package
// is considered international. // is considered international.
self.sender_country != self.recipient_country
} }
// TODO: Add the correct return type to the function signature. // TODO: Add the correct return type to the function signature.
fn get_fees(&self, cents_per_gram: u32) { fn get_fees(&self, cents_per_gram: u32) -> u32 {
// TODO: Calculate the package's fees. // TODO: Calculate the package's fees.
cents_per_gram * self.weight_in_grams
} }
} }
+5
View File
@@ -1,6 +1,11 @@
#[derive(Debug)] #[derive(Debug)]
enum Message { enum Message {
// TODO: Define a few types of messages as used below. // TODO: Define a few types of messages as used below.
Resize,
Move,
Echo,
ChangeColor,
Quit,
} }
fn main() { fn main() {
+5
View File
@@ -7,6 +7,11 @@ struct Point {
#[derive(Debug)] #[derive(Debug)]
enum Message { enum Message {
// TODO: Define the different variants used below. // TODO: Define the different variants used below.
Resize { width: usize, height: usize },
Move(Point),
Echo(String),
ChangeColor(u8, u8, u8),
Quit,
} }
impl Message { impl Message {
+7
View File
@@ -46,6 +46,13 @@ impl State {
fn process(&mut self, message: Message) { fn process(&mut self, message: Message) {
// TODO: Create a match expression to process the different message // TODO: Create a match expression to process the different message
// variants using the methods defined above. // variants using the methods defined above.
match message {
Message::Resize { width, height } => self.resize(width, height),
Message::Move(point) => self.move_position(point),
Message::Echo(string) => self.echo(string),
Message::ChangeColor(red, green, blue) => self.change_color(red, green, blue),
Message::Quit => self.quit(),
}
} }
} }
+1 -1
View File
@@ -1,5 +1,5 @@
// TODO: Fix the compiler error without changing the function signature. // TODO: Fix the compiler error without changing the function signature.
fn current_favorite_color() -> String { fn current_favorite_color() -> &'static str {
"blue" "blue"
} }
+1 -1
View File
@@ -6,7 +6,7 @@ fn is_a_color_word(attempt: &str) -> bool {
fn main() { fn main() {
let word = String::from("green"); // Don't change this line. let word = String::from("green"); // Don't change this line.
if is_a_color_word(word) { if is_a_color_word(&word) {
println!("That is a color word I know!"); println!("That is a color word I know!");
} else { } else {
println!("That is not a color word I know."); println!("That is not a color word I know.");
+3
View File
@@ -1,13 +1,16 @@
fn trim_me(input: &str) -> &str { fn trim_me(input: &str) -> &str {
// TODO: Remove whitespace from both ends of a string. // TODO: Remove whitespace from both ends of a string.
input.trim_ascii()
} }
fn compose_me(input: &str) -> String { fn compose_me(input: &str) -> String {
// TODO: Add " world!" to the string! There are multiple ways to do this. // TODO: Add " world!" to the string! There are multiple ways to do this.
input.to_owned() + " world!"
} }
fn replace_me(input: &str) -> String { fn replace_me(input: &str) -> String {
// TODO: Replace "cars" in the string with "balloons". // TODO: Replace "cars" in the string with "balloons".
input.to_owned().replace("cars", "balloons")
} }
fn main() { fn main() {
+10 -13
View File
@@ -1,6 +1,3 @@
// Calls of this function should be replaced with calls of `string_slice` or `string`.
fn placeholder() {}
fn string_slice(arg: &str) { fn string_slice(arg: &str) {
println!("{arg}"); println!("{arg}");
} }
@@ -13,25 +10,25 @@ fn string(arg: String) {
// Your task is to replace `placeholder(…)` with either `string_slice(…)` // Your task is to replace `placeholder(…)` with either `string_slice(…)`
// or `string(…)` depending on what you think each value is. // or `string(…)` depending on what you think each value is.
fn main() { fn main() {
placeholder("blue"); string_slice("blue"); // &str
placeholder("red".to_string()); string("red".to_string()); // String
placeholder(String::from("hi")); string(String::from("hi")); // String
placeholder("rust is fun!".to_owned()); string("rust is fun!".to_owned()); // String
placeholder("nice weather".into()); string("nice weather".into()); // String
placeholder(format!("Interpolation {}", "Station")); string(format!("Interpolation {}", "Station")); // String
// WARNING: This is byte indexing, not character indexing. // WARNING: This is byte indexing, not character indexing.
// Character indexing can be done using `s.chars().nth(INDEX)`. // Character indexing can be done using `s.chars().nth(INDEX)`.
placeholder(&String::from("abc")[0..1]); string_slice(&String::from("abc")[0..1]); // &str
placeholder(" hello there ".trim()); string_slice(" hello there ".trim()); // &str
placeholder("Happy Monday!".replace("Mon", "Tues")); string("Happy Monday!".replace("Mon", "Tues")); // String
placeholder("mY sHiFt KeY iS sTiCkY".to_lowercase()); string("mY sHiFt KeY iS sTiCkY".to_lowercase()); // String
} }
+1 -1
View File
@@ -5,7 +5,7 @@ mod sausage_factory {
String::from("Ginger") String::from("Ginger")
} }
fn make_sausage() { pub fn make_sausage() {
get_secret_recipe(); get_secret_recipe();
println!("sausage!"); println!("sausage!");
} }
+2 -2
View File
@@ -3,8 +3,8 @@
mod delicious_snacks { mod delicious_snacks {
// TODO: Add the following two `use` statements after fixing them. // TODO: Add the following two `use` statements after fixing them.
// use self::fruits::PEAR as ???; pub use self::fruits::PEAR as fruit;
// use self::veggies::CUCUMBER as ???; pub use self::veggies::CUCUMBER as veggie;
mod fruits { mod fruits {
pub const PEAR: &str = "Pear"; pub const PEAR: &str = "Pear";
+1 -1
View File
@@ -3,7 +3,7 @@
// TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into // TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into
// your scope. Bonus style points if you can do it with one line! // your scope. Bonus style points if you can do it with one line!
// use ???; use std::time::{SystemTime, UNIX_EPOCH};
fn main() { fn main() {
match SystemTime::now().duration_since(UNIX_EPOCH) { match SystemTime::now().duration_since(UNIX_EPOCH) {
+3 -1
View File
@@ -8,10 +8,12 @@ use std::collections::HashMap;
fn fruit_basket() -> HashMap<String, u32> { fn fruit_basket() -> HashMap<String, u32> {
// TODO: Declare the hash map. // TODO: Declare the hash map.
// let mut basket = let mut basket = HashMap::<String, u32>::new();
// Two bananas are already given for you :) // Two bananas are already given for you :)
basket.insert(String::from("banana"), 2); basket.insert(String::from("banana"), 2);
basket.insert(String::from("apple"), 2);
basket.insert(String::from("mango"), 2);
// TODO: Put more fruits in your basket. // TODO: Put more fruits in your basket.
+1
View File
@@ -32,6 +32,7 @@ fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
// TODO: Insert new fruits if they are not already present in the // TODO: Insert new fruits if they are not already present in the
// basket. Note that you are not allowed to put any type of fruit that's // basket. Note that you are not allowed to put any type of fruit that's
// already present! // already present!
basket.entry(fruit).or_insert(1);
} }
} }
+39 -3
View File
@@ -31,13 +31,47 @@ fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
// Keep in mind that goals scored by team 1 will be the number of goals // Keep in mind that goals scored by team 1 will be the number of goals
// conceded by team 2. Similarly, goals scored by team 2 will be the // conceded by team 2. Similarly, goals scored by team 2 will be the
// number of goals conceded by team 1. // number of goals conceded by team 1.
} scores
.entry(team_1_name)
.and_modify(|current_team_1_scores| {
current_team_1_scores.goals_scored += team_1_score;
current_team_1_scores.goals_conceded += team_2_score
})
.or_insert(TeamScores {
goals_scored: team_1_score,
goals_conceded: team_2_score,
});
scores
.entry(team_2_name)
.and_modify(|current_team_2_scores| {
current_team_2_scores.goals_scored += team_2_score;
current_team_2_scores.goals_conceded += team_1_score
})
.or_insert(TeamScores {
goals_scored: team_2_score,
goals_conceded: team_1_score,
});
}
scores scores
} }
fn main() { fn main() {
// You can optionally experiment here. // You can optionally experiment here.
const RESULTS: &str = "England,France,4,2
France,Italy,3,1
Poland,Spain,2,0
Germany,England,2,1
England,Spain,1,0";
let scores = build_scores_table(RESULTS);
for (key, value) in &scores {
println!(
"{key}: (scored: {0}, conceeded: {1})",
value.goals_scored, value.goals_conceded
);
}
} }
#[cfg(test)] #[cfg(test)]
@@ -54,9 +88,11 @@ England,Spain,1,0";
fn build_scores() { fn build_scores() {
let scores = build_scores_table(RESULTS); let scores = build_scores_table(RESULTS);
assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"] assert!(
["England", "France", "Germany", "Italy", "Poland", "Spain"]
.into_iter() .into_iter()
.all(|team_name| scores.contains_key(team_name))); .all(|team_name| scores.contains_key(team_name))
);
} }
#[test] #[test]
+6 -1
View File
@@ -4,6 +4,11 @@
// `hour_of_day` is higher than 23. // `hour_of_day` is higher than 23.
fn maybe_ice_cream(hour_of_day: u16) -> Option<u16> { fn maybe_ice_cream(hour_of_day: u16) -> Option<u16> {
// TODO: Complete the function body. // TODO: Complete the function body.
match hour_of_day {
0..22 => Some(5),
22..=23 => Some(0),
_ => None,
}
} }
fn main() { fn main() {
@@ -18,7 +23,7 @@ mod tests {
fn raw_value() { fn raw_value() {
// TODO: Fix this test. How do you get the value contained in the // TODO: Fix this test. How do you get the value contained in the
// Option? // Option?
let ice_creams = maybe_ice_cream(12); let ice_creams = maybe_ice_cream(12).unwrap();
assert_eq!(ice_creams, 5); // Don't change this line. assert_eq!(ice_creams, 5); // Don't change this line.
} }
+2 -2
View File
@@ -10,7 +10,7 @@ mod tests {
let optional_target = Some(target); let optional_target = Some(target);
// TODO: Make this an if-let statement whose value is `Some`. // TODO: Make this an if-let statement whose value is `Some`.
word = optional_target { if let Some(word) = optional_target {
assert_eq!(word, target); assert_eq!(word, target);
} }
} }
@@ -29,7 +29,7 @@ mod tests {
// TODO: Make this a while-let statement. Remember that `Vec::pop()` // TODO: Make this a while-let statement. Remember that `Vec::pop()`
// adds another layer of `Option`. You can do nested pattern matching // adds another layer of `Option`. You can do nested pattern matching
// in if-let and while-let statements. // in if-let and while-let statements.
integer = optional_integers.pop() { while let Some(Some(integer)) = optional_integers.pop() {
assert_eq!(integer, cursor); assert_eq!(integer, cursor);
cursor -= 1; cursor -= 1;
} }
+1 -1
View File
@@ -9,7 +9,7 @@ fn main() {
// TODO: Fix the compiler error by adding something to this match statement. // TODO: Fix the compiler error by adding something to this match statement.
match optional_point { match optional_point {
Some(p) => println!("Coordinates are {},{}", p.x, p.y), Some(ref p) => println!("Coordinates are {},{}", p.x, p.y),
_ => panic!("No match!"), _ => panic!("No match!"),
} }
+3 -3
View File
@@ -4,12 +4,12 @@
// construct to `Option` that can be used to express error conditions. Change // construct to `Option` that can be used to express error conditions. Change
// the function signature and body to return `Result<String, String>` instead // the function signature and body to return `Result<String, String>` instead
// of `Option<String>`. // of `Option<String>`.
fn generate_nametag_text(name: String) -> Option<String> { fn generate_nametag_text(name: String) -> Result<String, String> {
if name.is_empty() { if name.is_empty() {
// Empty names aren't allowed // Empty names aren't allowed
None Err("Empty names aren't allowed".into())
} else { } else {
Some(format!("Hi! My name is {name}")) Ok(format!("Hi! My name is {name}"))
} }
} }
+1 -1
View File
@@ -21,7 +21,7 @@ fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let cost_per_item = 5; let cost_per_item = 5;
// TODO: Handle the error case as described above. // TODO: Handle the error case as described above.
let qty = item_quantity.parse::<i32>(); let qty = item_quantity.parse::<i32>()?;
Ok(qty * cost_per_item + processing_fee) Ok(qty * cost_per_item + processing_fee)
} }
+3 -1
View File
@@ -15,7 +15,7 @@ fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
// TODO: Fix the compiler error by changing the signature and body of the // TODO: Fix the compiler error by changing the signature and body of the
// `main` function. // `main` function.
fn main() { fn main() -> Result<(), ParseIntError> {
let mut tokens = 100; let mut tokens = 100;
let pretend_user_input = "8"; let pretend_user_input = "8";
@@ -24,8 +24,10 @@ fn main() {
if cost > tokens { if cost > tokens {
println!("You can't afford that many!"); println!("You can't afford that many!");
Ok(())
} else { } else {
tokens -= cost; tokens -= cost;
println!("You now have {tokens} tokens."); println!("You now have {tokens} tokens.");
Ok(())
} }
} }
+5 -1
View File
@@ -11,7 +11,11 @@ impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<Self, CreationError> { fn new(value: i64) -> Result<Self, CreationError> {
// TODO: This function shouldn't always return an `Ok`. // TODO: This function shouldn't always return an `Ok`.
// Read the tests below to clarify what should be returned. // Read the tests below to clarify what should be returned.
Ok(Self(value as u64)) match value {
x if x < 0 => Err(CreationError::Negative),
0 => Err(CreationError::Zero),
x => Ok(PositiveNonzeroInteger(x as u64)),
}
} }
} }
+1 -1
View File
@@ -48,7 +48,7 @@ impl PositiveNonzeroInteger {
// TODO: Add the correct return type `Result<(), Box<dyn ???>>`. What can we // TODO: Add the correct return type `Result<(), Box<dyn ???>>`. What can we
// use to describe both errors? Is there a trait which both errors implement? // use to describe both errors? Is there a trait which both errors implement?
fn main() { fn main() -> Result<(), Box<dyn Error>> {
let pretend_user_input = "42"; let pretend_user_input = "42";
let x: i64 = pretend_user_input.parse()?; let x: i64 = pretend_user_input.parse()?;
println!("output={:?}", PositiveNonzeroInteger::new(x)?); println!("output={:?}", PositiveNonzeroInteger::new(x)?);
+4 -2
View File
@@ -25,7 +25,9 @@ impl ParsePosNonzeroError {
} }
// TODO: Add another error conversion function here. // TODO: Add another error conversion function here.
// fn from_parse_int(???) -> Self { ??? } fn from_parse_int(err: ParseIntError) -> Self {
Self::ParseInt(err)
}
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
@@ -43,7 +45,7 @@ impl PositiveNonzeroInteger {
fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> { fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
// TODO: change this to return an appropriate error instead of panicking // TODO: change this to return an appropriate error instead of panicking
// when `parse()` returns an error. // when `parse()` returns an error.
let x: i64 = s.parse().unwrap(); let x: i64 = s.parse().map_err(ParsePosNonzeroError::from_parse_int)?;
Self::new(x).map_err(ParsePosNonzeroError::from_creation) Self::new(x).map_err(ParsePosNonzeroError::from_creation)
} }
} }
+1 -1
View File
@@ -6,7 +6,7 @@ fn main() {
// TODO: Fix the compiler error by annotating the type of the vector // TODO: Fix the compiler error by annotating the type of the vector
// `Vec<T>`. Choose `T` as some integer type that can be created from // `Vec<T>`. Choose `T` as some integer type that can be created from
// `u8` and `i8`. // `u8` and `i8`.
let mut numbers = Vec::new(); let mut numbers: Vec<i32> = Vec::new();
// Don't change the lines below. // Don't change the lines below.
let n1: u8 = 42; let n1: u8 = 42;
+4 -4
View File
@@ -1,12 +1,12 @@
// This powerful wrapper provides the ability to store a positive integer value. // This powerful wrapper provides the ability to store a positive integer value.
// TODO: Rewrite it using a generic so that it supports wrapping ANY type. // TODO: Rewrite it using a generic so that it supports wrapping ANY type.
struct Wrapper { struct Wrapper<T> {
value: u32, value: T,
} }
// TODO: Adapt the struct's implementation to be generic over the wrapped value. // TODO: Adapt the struct's implementation to be generic over the wrapped value.
impl Wrapper { impl<T> Wrapper<T> {
fn new(value: u32) -> Self { fn new(value: T) -> Self {
Wrapper { value } Wrapper { value }
} }
} }
+3
View File
@@ -6,6 +6,9 @@ trait AppendBar {
impl AppendBar for String { impl AppendBar for String {
// TODO: Implement `AppendBar` for the type `String`. // TODO: Implement `AppendBar` for the type `String`.
fn append_bar(self) -> String {
self + "Bar"
}
} }
fn main() { fn main() {
+6
View File
@@ -4,6 +4,12 @@ trait AppendBar {
// TODO: Implement the trait `AppendBar` for a vector of strings. // TODO: Implement the trait `AppendBar` for a vector of strings.
// `append_bar` should push the string "Bar" into the vector. // `append_bar` should push the string "Bar" into the vector.
impl AppendBar for Vec<String> {
fn append_bar(mut self) -> Self {
self.push("Bar".into());
self
}
}
fn main() { fn main() {
// You can optionally experiment here. // You can optionally experiment here.
+6 -1
View File
@@ -3,7 +3,9 @@ trait Licensed {
// implementors like the two structs below can share that default behavior // implementors like the two structs below can share that default behavior
// without repeating the function. // without repeating the function.
// The default license information should be the string "Default license". // The default license information should be the string "Default license".
fn licensing_info(&self) -> String; fn licensing_info(&self) -> String {
"Default license".into()
}
} }
struct SomeSoftware { struct SomeSoftware {
@@ -28,10 +30,13 @@ mod tests {
#[test] #[test]
fn is_licensing_info_the_same() { fn is_licensing_info_the_same() {
let licensing_info = "Default license"; let licensing_info = "Default license";
let some_software = SomeSoftware { version_number: 1 }; let some_software = SomeSoftware { version_number: 1 };
let other_software = OtherSoftware { let other_software = OtherSoftware {
version_number: "v2.0.0".to_string(), version_number: "v2.0.0".to_string(),
}; };
assert_eq!(some_software.licensing_info(), licensing_info); assert_eq!(some_software.licensing_info(), licensing_info);
assert_eq!(other_software.licensing_info(), licensing_info); assert_eq!(other_software.licensing_info(), licensing_info);
} }
+1 -1
View File
@@ -11,7 +11,7 @@ impl Licensed for SomeSoftware {}
impl Licensed for OtherSoftware {} impl Licensed for OtherSoftware {}
// TODO: Fix the compiler error by only changing the signature of this function. // TODO: Fix the compiler error by only changing the signature of this function.
fn compare_license_types(software1: ???, software2: ???) -> bool { fn compare_license_types(software1: impl Licensed, software2: impl Licensed) -> bool {
software1.licensing_info() == software2.licensing_info() software1.licensing_info() == software2.licensing_info()
} }
+1 -1
View File
@@ -19,7 +19,7 @@ impl SomeTrait for OtherStruct {}
impl OtherTrait for OtherStruct {} impl OtherTrait for OtherStruct {}
// TODO: Fix the compiler error by only changing the signature of this function. // TODO: Fix the compiler error by only changing the signature of this function.
fn some_func(item: ???) -> bool { fn some_func(item: impl SomeTrait + OtherTrait) -> bool {
item.some_function() && item.other_function() item.some_function() && item.other_function()
} }
+2 -6
View File
@@ -4,12 +4,8 @@
// not own their own data. What if their owner goes out of scope? // not own their own data. What if their owner goes out of scope?
// TODO: Fix the compiler error by updating the function signature. // TODO: Fix the compiler error by updating the function signature.
fn longest(x: &str, y: &str) -> &str { fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { if x.len() > y.len() { x } else { y }
x
} else {
y
}
} }
fn main() { fn main() {
+2 -6
View File
@@ -1,19 +1,15 @@
// Don't change this function. // Don't change this function.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { if x.len() > y.len() { x } else { y }
x
} else {
y
}
} }
fn main() { fn main() {
// TODO: Fix the compiler error by moving one line. // TODO: Fix the compiler error by moving one line.
let string1 = String::from("long string is long"); let string1 = String::from("long string is long");
let string2 = String::from("xyz");
let result; let result;
{ {
let string2 = String::from("xyz");
result = longest(&string1, &string2); result = longest(&string1, &string2);
} }
println!("The longest string is '{result}'"); println!("The longest string is '{result}'");
+3 -3
View File
@@ -1,9 +1,9 @@
// Lifetimes are also needed when structs hold references. // Lifetimes are also needed when structs hold references.
// TODO: Fix the compiler errors about the struct. // TODO: Fix the compiler errors about the struct.
struct Book { struct Book<'a> {
author: &str, author: &'a str,
title: &str, title: &'a str,
} }
fn main() { fn main() {
+3 -2
View File
@@ -13,11 +13,12 @@ fn main() {
mod tests { mod tests {
// TODO: Import `is_even`. You can use a wildcard to import everything in // TODO: Import `is_even`. You can use a wildcard to import everything in
// the outer module. // the outer module.
use super::is_even;
#[test] #[test]
fn you_can_assert() { fn you_can_assert() {
// TODO: Test the function `is_even` with some values. // TODO: Test the function `is_even` with some values.
assert!(); assert!(is_even(12));
assert!(); assert!(!is_even(13));
} }
} }
+4 -4
View File
@@ -15,9 +15,9 @@ mod tests {
#[test] #[test]
fn you_can_assert_eq() { fn you_can_assert_eq() {
// TODO: Test the function `power_of_2` with some values. // TODO: Test the function `power_of_2` with some values.
assert_eq!(); assert_eq!(power_of_2(0), 1);
assert_eq!(); assert_eq!(power_of_2(1), 2);
assert_eq!(); assert_eq!(power_of_2(2), 4);
assert_eq!(); assert_eq!(power_of_2(3), 8);
} }
} }
+4 -2
View File
@@ -29,13 +29,14 @@ mod tests {
// TODO: This test should check if the rectangle has the size that we // TODO: This test should check if the rectangle has the size that we
// pass to its constructor. // pass to its constructor.
let rect = Rectangle::new(10, 20); let rect = Rectangle::new(10, 20);
assert_eq!(todo!(), 10); // Check width assert_eq!(rect.width, 10); // Check width
assert_eq!(todo!(), 20); // Check height assert_eq!(rect.height, 20); // Check height
} }
// TODO: This test should check if the program panics when we try to create // TODO: This test should check if the program panics when we try to create
// a rectangle with negative width. // a rectangle with negative width.
#[test] #[test]
#[should_panic]
fn negative_width() { fn negative_width() {
let _rect = Rectangle::new(-10, 10); let _rect = Rectangle::new(-10, 10);
} }
@@ -43,6 +44,7 @@ mod tests {
// TODO: This test should check if the program panics when we try to create // TODO: This test should check if the program panics when we try to create
// a rectangle with negative height. // a rectangle with negative height.
#[test] #[test]
#[should_panic]
fn negative_height() { fn negative_height() {
let _rect = Rectangle::new(10, -10); let _rect = Rectangle::new(10, -10);
} }
+4 -4
View File
@@ -13,13 +13,13 @@ mod tests {
let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"]; let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"];
// TODO: Create an iterator over the array. // TODO: Create an iterator over the array.
let mut fav_fruits_iterator = todo!(); let mut fav_fruits_iterator = my_fav_fruits.iter();
assert_eq!(fav_fruits_iterator.next(), Some(&"banana")); assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()` assert_eq!(fav_fruits_iterator.next(), Some(&"custard apple")); // TODO: Replace `todo!()`
assert_eq!(fav_fruits_iterator.next(), Some(&"avocado")); assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()` assert_eq!(fav_fruits_iterator.next(), Some(&"peach")); // TODO: Replace `todo!()`
assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry")); assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()` assert_eq!(fav_fruits_iterator.next(), None); // TODO: Replace `todo!()`
} }
} }
+4 -3
View File
@@ -5,9 +5,10 @@
// "hello" -> "Hello" // "hello" -> "Hello"
fn capitalize_first(input: &str) -> String { fn capitalize_first(input: &str) -> String {
let mut chars = input.chars(); let mut chars = input.chars();
match chars.next() { match chars.next() {
None => String::new(), None => String::new(),
Some(first) => todo!(), Some(first) => first.to_uppercase().chain(chars).collect(),
} }
} }
@@ -15,14 +16,14 @@ fn capitalize_first(input: &str) -> String {
// Return a vector of strings. // Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"] // ["hello", "world"] -> ["Hello", "World"]
fn capitalize_words_vector(words: &[&str]) -> Vec<String> { fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
// ??? words.iter().map(|word| capitalize_first(word)).collect()
} }
// TODO: Apply the `capitalize_first` function again to a slice of string // TODO: Apply the `capitalize_first` function again to a slice of string
// slices. Return a single string. // slices. Return a single string.
// ["hello", " ", "world"] -> "Hello World" // ["hello", " ", "world"] -> "Hello World"
fn capitalize_words_string(words: &[&str]) -> String { fn capitalize_words_string(words: &[&str]) -> String {
// ??? words.iter().map(|word| capitalize_first(word)).collect()
} }
fn main() { fn main() {
+20 -5
View File
@@ -11,21 +11,36 @@ enum DivisionError {
// TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`. // TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
// Otherwise, return a suitable error. // Otherwise, return a suitable error.
fn divide(a: i64, b: i64) -> Result<i64, DivisionError> { fn divide(a: i64, b: i64) -> Result<i64, DivisionError> {
todo!(); match (a, b) {
(_, 0) => Err(DivisionError::DivideByZero),
(a, b) if a == i64::MIN && b == -1 => Err(DivisionError::IntegerOverflow),
(a, b) if a % b != 0 => Err(DivisionError::NotDivisible),
(a, b) => Ok(a / b),
}
} }
// TODO: Add the correct return type and complete the function body. // TODO: Add the correct return type and complete the function body.
// Desired output: `Ok([1, 11, 1426, 3])` // Desired output: `Ok([1, 11, 1426, 3])`
fn result_with_list() { fn result_with_list() -> Result<Vec<i64>, DivisionError> {
let numbers = [27, 297, 38502, 81]; let numbers = [27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27)); let result: Vec<i64> = numbers
.into_iter()
.map(|n| divide(n, 27))
.collect::<Result<Vec<i64>, DivisionError>>()?;
Ok(result)
} }
// TODO: Add the correct return type and complete the function body. // TODO: Add the correct return type and complete the function body.
// Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]` // Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]`
fn list_of_results() { fn list_of_results() -> Vec<Result<i64, DivisionError>> {
let numbers = [27, 297, 38502, 81]; let numbers = [27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27)); let division_results: Vec<Result<i64, DivisionError>> = numbers
.into_iter()
.map(|n| divide(n, 27))
.collect::<Vec<Result<i64, DivisionError>>>();
division_results
} }
fn main() { fn main() {
+1
View File
@@ -10,6 +10,7 @@ fn factorial(num: u64) -> u64 {
// - additional variables // - additional variables
// For an extra challenge, don't use: // For an extra challenge, don't use:
// - recursion // - recursion
(1..=num).fold(1, |acc, e| acc * e)
} }
fn main() { fn main() {
+8
View File
@@ -28,6 +28,9 @@ fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize { fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
// `map` is a hash map with `String` keys and `Progress` values. // `map` is a hash map with `String` keys and `Progress` values.
// map = { "variables1": Complete, "from_str": None, … } // map = { "variables1": Complete, "from_str": None, … }
map.values()
.filter(|excercise| **excercise == value)
.count()
} }
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize { fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
@@ -48,6 +51,11 @@ fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Pr
// `collection` is a slice of hash maps. // `collection` is a slice of hash maps.
// collection = [{ "variables1": Complete, "from_str": None, … }, // collection = [{ "variables1": Complete, "from_str": None, … },
// { "variables2": Complete, … }, … ] // { "variables2": Complete, … }, … ]
collection
.iter()
.flatten()
.filter(|excercise| *excercise.1 == value)
.count()
} }
fn main() { fn main() {
+2 -2
View File
@@ -23,13 +23,13 @@ fn main() {
let numbers: Vec<_> = (0..100u32).collect(); let numbers: Vec<_> = (0..100u32).collect();
// TODO: Define `shared_numbers` by using `Arc`. // TODO: Define `shared_numbers` by using `Arc`.
// let shared_numbers = ???; let shared_numbers = Arc::new(numbers);
let mut join_handles = Vec::new(); let mut join_handles = Vec::new();
for offset in 0..8 { for offset in 0..8 {
// TODO: Define `child_numbers` using `shared_numbers`. // TODO: Define `child_numbers` using `shared_numbers`.
// let child_numbers = ???; let child_numbers = Arc::clone(&shared_numbers);
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum(); let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
+3 -3
View File
@@ -12,18 +12,18 @@
// TODO: Use a `Box` in the enum definition to make the code compile. // TODO: Use a `Box` in the enum definition to make the code compile.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
enum List { enum List {
Cons(i32, List), Cons(i32, Box<List>),
Nil, Nil,
} }
// TODO: Create an empty cons list. // TODO: Create an empty cons list.
fn create_empty_list() -> List { fn create_empty_list() -> List {
todo!() List::Nil
} }
// TODO: Create a non-empty cons list. // TODO: Create a non-empty cons list.
fn create_non_empty_list() -> List { fn create_non_empty_list() -> List {
todo!() List::Cons(64, Box::new(List::Nil))
} }
fn main() { fn main() {
+3 -3
View File
@@ -39,7 +39,7 @@ mod tests {
let mut input = Cow::from(&vec); let mut input = Cow::from(&vec);
abs_all(&mut input); abs_all(&mut input);
// TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`. // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
assert!(matches!(input, todo!())); assert!(matches!(input, Cow::Borrowed(_)));
} }
#[test] #[test]
@@ -52,7 +52,7 @@ mod tests {
let mut input = Cow::from(vec); let mut input = Cow::from(vec);
abs_all(&mut input); abs_all(&mut input);
// TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`. // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
assert!(matches!(input, todo!())); assert!(matches!(input, Cow::Owned(_)));
} }
#[test] #[test]
@@ -64,6 +64,6 @@ mod tests {
let mut input = Cow::from(vec); let mut input = Cow::from(vec);
abs_all(&mut input); abs_all(&mut input);
// TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`. // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
assert!(matches!(input, todo!())); assert!(matches!(input, Cow::Owned(_)));
} }
} }
+6 -6
View File
@@ -60,17 +60,17 @@ mod tests {
jupiter.details(); jupiter.details();
// TODO // TODO
let saturn = Planet::Saturn(Rc::new(Sun)); let saturn = Planet::Saturn(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
saturn.details(); saturn.details();
// TODO // TODO
let uranus = Planet::Uranus(Rc::new(Sun)); let uranus = Planet::Uranus(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
uranus.details(); uranus.details();
// TODO // TODO
let neptune = Planet::Neptune(Rc::new(Sun)); let neptune = Planet::Neptune(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
neptune.details(); neptune.details();
@@ -91,13 +91,13 @@ mod tests {
drop(mars); drop(mars);
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
// TODO drop(earth);
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
// TODO drop(venus);
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
// TODO drop(mercury);
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
assert_eq!(Rc::strong_count(&sun), 1); assert_eq!(Rc::strong_count(&sun), 1);
+3 -1
View File
@@ -20,10 +20,12 @@ fn main() {
handles.push(handle); handles.push(handle);
} }
let mut results = Vec::new(); let mut results: Vec<_> = Vec::<_>::new();
for handle in handles { for handle in handles {
// TODO: Collect the results of all threads into the `results` vector. // TODO: Collect the results of all threads into the `results` vector.
// Use the `JoinHandle` struct which is returned by `thread::spawn`. // Use the `JoinHandle` struct which is returned by `thread::spawn`.
results.push(handle.join().unwrap())
} }
if results.len() != 10 { if results.len() != 10 {
+13 -4
View File
@@ -2,24 +2,31 @@
// work. But this time, the spawned threads need to be in charge of updating a // work. But this time, the spawned threads need to be in charge of updating a
// shared value: `JobStatus.jobs_done` // shared value: `JobStatus.jobs_done`
use std::{sync::Arc, thread, time::Duration}; use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
};
#[derive(Debug)]
struct JobStatus { struct JobStatus {
jobs_done: u32, jobs_done: u32,
} }
fn main() { fn main() {
// TODO: `Arc` isn't enough if you want a **mutable** shared state. // TODO: `Arc` isn't enough if you want a **mutable** shared state.
let status = Arc::new(JobStatus { jobs_done: 0 }); let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
let mut handles = Vec::new(); let mut handles = Vec::new();
for _ in 0..10 { for _ in 0..10 {
let status_shared = Arc::clone(&status); let status_shared = Arc::clone(&status);
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
// TODO: You must take an action before you update a shared value. // TODO: You must take an action before you update a shared value.
status_shared.jobs_done += 1; let mut acquired_status = status_shared.lock().unwrap();
acquired_status.jobs_done += 1;
}); });
handles.push(handle); handles.push(handle);
} }
@@ -30,5 +37,7 @@ fn main() {
} }
// TODO: Print the value of `JobStatus.jobs_done`. // TODO: Print the value of `JobStatus.jobs_done`.
println!("Jobs done: {}", todo!()); let mutex = Arc::try_unwrap(status).unwrap();
let job_status = mutex.into_inner().unwrap();
println!("Jobs done: {}", job_status.jobs_done);
} }
+7 -2
View File
@@ -17,18 +17,23 @@ impl Queue {
fn send_tx(q: Queue, tx: mpsc::Sender<u32>) { fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
// TODO: We want to send `tx` to both threads. But currently, it is moved // TODO: We want to send `tx` to both threads. But currently, it is moved
// into the first thread. How could you solve this problem? // into the first thread. How could you solve this problem?
let transmission = tx.clone();
thread::spawn(move || { thread::spawn(move || {
for val in q.first_half { for val in q.first_half {
println!("Sending {val:?}"); println!("Sending {val:?}");
tx.send(val).unwrap(); transmission.send(val).unwrap();
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
} }
}); });
let transmission = tx.clone();
thread::spawn(move || { thread::spawn(move || {
for val in q.second_half { for val in q.second_half {
println!("Sending {val:?}"); println!("Sending {val:?}");
tx.send(val).unwrap(); transmission.send(val).unwrap();
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
} }
}); });
+1 -1
View File
@@ -6,5 +6,5 @@ macro_rules! my_macro {
fn main() { fn main() {
// TODO: Fix the macro call. // TODO: Fix the macro call.
my_macro(); my_macro!();
} }
+4 -4
View File
@@ -1,10 +1,10 @@
fn main() {
my_macro!();
}
// TODO: Fix the compiler error by moving the whole definition of this macro. // TODO: Fix the compiler error by moving the whole definition of this macro.
macro_rules! my_macro { macro_rules! my_macro {
() => { () => {
println!("Check out my macro!"); println!("Check out my macro!");
}; };
} }
fn main() {
my_macro!();
}
+1
View File
@@ -1,6 +1,7 @@
// TODO: Fix the compiler error without taking the macro definition out of this // TODO: Fix the compiler error without taking the macro definition out of this
// module. // module.
mod macros { mod macros {
#[macro_export]
macro_rules! my_macro { macro_rules! my_macro {
() => { () => {
println!("Check out my macro!"); println!("Check out my macro!");
+1 -1
View File
@@ -3,7 +3,7 @@
macro_rules! my_macro { macro_rules! my_macro {
() => { () => {
println!("Check out my macro!"); println!("Check out my macro!");
} };
($val:expr) => { ($val:expr) => {
println!("Look at this other macro: {}", $val); println!("Look at this other macro: {}", $val);
} }
+1 -1
View File
@@ -6,7 +6,7 @@
fn main() { fn main() {
// TODO: Fix the Clippy lint in this line. // TODO: Fix the Clippy lint in this line.
let pi = 3.14; let pi = std::f32::consts::PI;
let radius: f32 = 5.0; let radius: f32 = 5.0;
let area = pi * radius.powi(2); let area = pi * radius.powi(2);
+2 -1
View File
@@ -1,8 +1,9 @@
fn main() { fn main() {
let mut res = 42; let mut res = 42;
let option = Some(12); let option = Some(12);
// TODO: Fix the Clippy lint. // TODO: Fix the Clippy lint.
for x in option { if let Some(x) = option {
res += x; res += x;
} }
+6 -6
View File
@@ -7,23 +7,23 @@ fn main() {
let my_option: Option<&str> = None; let my_option: Option<&str> = None;
// Assume that you don't know the value of `my_option`. // Assume that you don't know the value of `my_option`.
// In the case of `Some`, we want to print its value. // In the case of `Some`, we want to print its value.
if my_option.is_none() { if let Some(my_option) = my_option {
println!("{}", my_option.unwrap()); println!("{}", my_option);
} }
let my_arr = &[ let my_arr = &[
-1, -2, -3 -1, -2, -3,
-4, -5, -6 -4, -5, -6
]; ];
println!("My array! Here it is: {my_arr:?}"); println!("My array! Here it is: {my_arr:?}");
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5); let my_empty_vec = ();
vec![1, 2, 3, 4, 5].resize(0, 5);
println!("This Vec is empty, see? {my_empty_vec:?}"); println!("This Vec is empty, see? {my_empty_vec:?}");
let mut value_a = 45; let mut value_a = 45;
let mut value_b = 66; let mut value_b = 66;
// Let's swap these two! // Let's swap these two!
value_a = value_b; std::mem::swap(&mut value_a, &mut value_b);
value_b = value_a;
println!("value a: {value_a}; value b: {value_b}"); println!("value a: {value_a}; value b: {value_b}");
} }
+5 -3
View File
@@ -5,20 +5,22 @@
// Obtain the number of bytes (not characters) in the given argument // Obtain the number of bytes (not characters) in the given argument
// (`.len()` returns the number of bytes in a string). // (`.len()` returns the number of bytes in a string).
// TODO: Add the `AsRef` trait appropriately as a trait bound. // TODO: Add the `AsRef` trait appropriately as a trait bound.
fn byte_counter<T>(arg: T) -> usize { fn byte_counter<T: AsRef<str>>(arg: T) -> usize {
arg.as_ref().len() arg.as_ref().len()
} }
// Obtain the number of characters (not bytes) in the given argument. // Obtain the number of characters (not bytes) in the given argument.
// TODO: Add the `AsRef` trait appropriately as a trait bound. // TODO: Add the `AsRef` trait appropriately as a trait bound.
fn char_counter<T>(arg: T) -> usize { fn char_counter<T: AsRef<str>>(arg: T) -> usize {
arg.as_ref().chars().count() arg.as_ref().chars().count()
} }
// Squares a number using `as_mut()`. // Squares a number using `as_mut()`.
// TODO: Add the appropriate trait bound. // TODO: Add the appropriate trait bound.
fn num_sq<T>(arg: &mut T) { fn num_sq<T: AsMut<u32>>(arg: &mut T) {
// TODO: Implement the function body. // TODO: Implement the function body.
let val = *arg.as_mut();
*arg.as_mut() = val * val;
} }
fn main() { fn main() {
+12 -1
View File
@@ -34,7 +34,18 @@ impl Default for Person {
// 5. Parse the second element from the split operation into a `u8` as the age. // 5. Parse the second element from the split operation into a `u8` as the age.
// 6. If parsing the age fails, return the default of `Person`. // 6. If parsing the age fails, return the default of `Person`.
impl From<&str> for Person { impl From<&str> for Person {
fn from(s: &str) -> Self {} fn from(s: &str) -> Self {
match s.split(",").collect::<Vec<&str>>().as_slice() {
[name, age] if (!name.is_empty() && !age.is_empty()) => match age.parse::<u8>() {
Ok(age) => Person {
name: name.to_string(),
age,
},
Err(_) => Person::default(),
},
_ => Person::default(),
}
}
} }
fn main() { fn main() {
+13 -1
View File
@@ -41,7 +41,19 @@ enum ParsePersonError {
impl FromStr for Person { impl FromStr for Person {
type Err = ParsePersonError; type Err = ParsePersonError;
fn from_str(s: &str) -> Result<Self, Self::Err> {} fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.split(",").collect::<Vec<&str>>().as_slice() {
[name, age] if (!name.is_empty()) => match age.parse::<u8>() {
Ok(age) => Ok(Person {
name: name.to_string(),
age,
}),
Err(err) => Err(ParsePersonError::ParseInt(err)),
},
["", _] => Err(ParsePersonError::NoName),
_ => Err(ParsePersonError::BadLen),
}
}
} }
fn main() { fn main() {
+50 -3
View File
@@ -28,14 +28,45 @@ enum IntoColorError {
impl TryFrom<(i16, i16, i16)> for Color { impl TryFrom<(i16, i16, i16)> for Color {
type Error = IntoColorError; type Error = IntoColorError;
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {} fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
match tuple {
(red, green, blue)
if (0..=255).contains(&red)
&& (0..=255).contains(&green)
&& (0..=255).contains(&blue) =>
{
Ok(Color {
red: red as u8,
green: green as u8,
blue: blue as u8,
})
}
_ => Err(IntoColorError::IntConversion),
}
}
} }
// TODO: Array implementation. // TODO: Array implementation.
impl TryFrom<[i16; 3]> for Color { impl TryFrom<[i16; 3]> for Color {
type Error = IntoColorError; type Error = IntoColorError;
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {} fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
match arr.as_slice() {
[red, green, blue] => {
if (0..=255).contains(red) && (0..=255).contains(green) && (0..=255).contains(blue)
{
Ok(Color {
red: *red as u8,
green: *green as u8,
blue: *blue as u8,
})
} else {
Err(IntoColorError::IntConversion)
}
}
_ => Err(IntoColorError::BadLen),
}
}
} }
// TODO: Slice implementation. // TODO: Slice implementation.
@@ -43,7 +74,23 @@ impl TryFrom<[i16; 3]> for Color {
impl TryFrom<&[i16]> for Color { impl TryFrom<&[i16]> for Color {
type Error = IntoColorError; type Error = IntoColorError;
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {} fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
match slice {
[red, green, blue] => {
if (0..=255).contains(red) && (0..=255).contains(green) && (0..=255).contains(blue)
{
Ok(Color {
red: *red as u8,
green: *green as u8,
blue: *blue as u8,
})
} else {
Err(IntoColorError::IntConversion)
}
}
_ => Err(IntoColorError::BadLen),
}
}
} }
fn main() { fn main() {
+1 -1
View File
@@ -5,7 +5,7 @@
fn average(values: &[f64]) -> f64 { fn average(values: &[f64]) -> f64 {
let total = values.iter().sum::<f64>(); let total = values.iter().sum::<f64>();
// TODO: Make a conversion before dividing. // TODO: Make a conversion before dividing.
total / values.len() total / values.len() as f64
} }
fn main() { fn main() {
+16 -2
View File
@@ -27,7 +27,21 @@ mod my_module {
use super::Command; use super::Command;
// TODO: Complete the function as described above. // TODO: Complete the function as described above.
// pub fn transformer(input: ???) -> ??? { ??? } pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
let mut output: Vec<String> = Vec::new();
for (string, command) in input {
match command {
Command::Uppercase => output.push(string.to_uppercase()),
Command::Trim => output.push(string.trim().into()),
Command::Append(number_of_times_bar_will_be_added) => {
output.push(string + &"bar".repeat(number_of_times_bar_will_be_added))
}
}
}
output
}
} }
fn main() { fn main() {
@@ -37,8 +51,8 @@ fn main() {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
// TODO: What do we need to import to have `transformer` in scope? // TODO: What do we need to import to have `transformer` in scope?
// use ???;
use super::Command; use super::Command;
use super::my_module::transformer;
#[test] #[test]
fn it_works() { fn it_works() {
+4 -3
View File
@@ -10,16 +10,17 @@
// //
// Make the necessary code changes in the struct `ReportCard` and the impl // Make the necessary code changes in the struct `ReportCard` and the impl
// block to support alphabetical report cards in addition to numerical ones. // block to support alphabetical report cards in addition to numerical ones.
use std::fmt::Display;
// TODO: Adjust the struct as described above. // TODO: Adjust the struct as described above.
struct ReportCard { struct ReportCard<G: Display> {
grade: f32, grade: G,
student_name: String, student_name: String,
student_age: u8, student_age: u8,
} }
// TODO: Adjust the impl block as described above. // TODO: Adjust the impl block as described above.
impl ReportCard { impl<G: Display> ReportCard<G> {
fn print(&self) -> String { fn print(&self) -> String {
format!( format!(
"{} ({}) - achieved a grade of {}", "{} ({}) - achieved a grade of {}",