Finish exercises

This commit is contained in:
Yuhua Mai 2020-05-16 11:52:56 -07:00
parent 58fc67525b
commit 9d46b94f9f
15 changed files with 134 additions and 76 deletions

View File

@ -2,16 +2,15 @@
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html // Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively. // and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
// I AM NOT DONE
// Obtain the number of bytes (not characters) in the given argument // Obtain the number of bytes (not characters) in the given argument
// Add the AsRef trait appropriately as a trait bound // 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().as_bytes().len() arg.as_ref().as_bytes().len()
} }
// Obtain the number of characters (not bytes) in the given argument // Obtain the number of characters (not bytes) in the given argument
// Add the AsRef trait appropriately as a trait bound // 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()
} }

View File

@ -18,7 +18,6 @@ impl Default for Person {
} }
} }
// I AM NOT DONE
// Your task is to complete this implementation // Your task is to complete this implementation
// in order for the line `let p = Person::from("Mark,20")` to compile // in order for the line `let p = Person::from("Mark,20")` to compile
// Please note that you'll need to parse the age component into a `usize` // Please note that you'll need to parse the age component into a `usize`
@ -34,6 +33,18 @@ impl Default for Person {
// Otherwise, then return an instantiated Person onject with the results // Otherwise, then return an instantiated Person onject with the results
impl From<&str> for Person { impl From<&str> for Person {
fn from(s: &str) -> Person { fn from(s: &str) -> Person {
if s.is_empty() {
return Default::default();
}
let splits: Vec<&str> = s.split(",").collect::<Vec<&str>>();
let name = splits[0].to_string();
let age_result = splits[1].parse::<usize>();
match age_result {
Ok(age) => Person { name, age },
Error => Default::default(),
}
} }
} }
@ -49,6 +60,7 @@ fn main() {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_default() { fn test_default() {
// Test that the default person is 30 year old John // Test that the default person is 30 year old John
@ -56,6 +68,7 @@ mod tests {
assert_eq!(dp.name, "John"); assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30); assert_eq!(dp.age, 30);
} }
#[test] #[test]
fn test_bad_convert() { fn test_bad_convert() {
// Test that John is returned when bad string is provided // Test that John is returned when bad string is provided
@ -63,6 +76,7 @@ mod tests {
assert_eq!(p.name, "John"); assert_eq!(p.name, "John");
assert_eq!(p.age, 30); assert_eq!(p.age, 30);
} }
#[test] #[test]
fn test_good_convert() { fn test_good_convert() {
// Test that "Mark,20" works // Test that "Mark,20" works
@ -70,6 +84,7 @@ mod tests {
assert_eq!(p.name, "Mark"); assert_eq!(p.name, "Mark");
assert_eq!(p.age, 20); assert_eq!(p.age, 20);
} }
#[test] #[test]
fn test_bad_age() { fn test_bad_age() {
// Test that "Mark.twenty" will return the default person due to an error in parsing age // Test that "Mark.twenty" will return the default person due to an error in parsing age

View File

@ -10,7 +10,6 @@ struct Person {
age: usize, age: usize,
} }
// I AM NOT DONE
// Steps: // Steps:
// 1. If the length of the provided string is 0, then return an error // 1. If the length of the provided string is 0, then return an error
// 2. Split the given string on the commas present in it // 2. Split the given string on the commas present in it
@ -21,6 +20,18 @@ struct Person {
impl FromStr for Person { impl FromStr for Person {
type Err = String; type Err = String;
fn from_str(s: &str) -> Result<Person, Self::Err> { fn from_str(s: &str) -> Result<Person, Self::Err> {
if s.is_empty() {
return Err("empty &str".to_string());
}
let splits: Vec<&str> = s.split(",").collect::<Vec<&str>>();
let name = splits[0].to_string();
let age_result = splits[1].parse::<usize>();
match age_result {
Ok(age) => Ok(Person { name, age }),
Error => Err("incorrect age".to_string()),
}
} }
} }
@ -46,4 +57,4 @@ mod tests {
fn missing_age() { fn missing_age() {
"John".parse::<Person>().unwrap(); "John".parse::<Person>().unwrap();
} }
} }

View File

@ -2,7 +2,7 @@
// Basically, this is the same as From. The main difference is that this should return a Result type // Basically, this is the same as From. The main difference is that this should return a Result type
// instead of the target type itself. // instead of the target type itself.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html // You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
use std::convert::{TryInto, TryFrom}; use std::convert::{TryFrom, TryInto};
#[derive(Debug)] #[derive(Debug)]
struct Person { struct Person {
@ -10,7 +10,6 @@ struct Person {
age: usize, age: usize,
} }
// I AM NOT DONE
// Your task is to complete this implementation // Your task is to complete this implementation
// in order for the line `let p = Person::try_from("Mark,20")` to compile // in order for the line `let p = Person::try_from("Mark,20")` to compile
// and return an Ok result of inner type Person. // and return an Ok result of inner type Person.
@ -28,6 +27,18 @@ struct Person {
impl TryFrom<&str> for Person { impl TryFrom<&str> for Person {
type Error = String; type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> { fn try_from(s: &str) -> Result<Self, Self::Error> {
if s.is_empty() {
return Err("empty &str".to_string());
}
let splits: Vec<&str> = s.split(",").collect::<Vec<&str>>();
let name = splits[0].to_string();
let age_result = splits[1].parse::<usize>();
match age_result {
Ok(age) => Ok(Person { name, age }),
Error => Err("incorrect age".to_string()),
}
} }
} }
@ -68,4 +79,4 @@ mod tests {
fn test_panic_bad_age() { fn test_panic_bad_age() {
let p = Person::try_from("Mark,twenty").unwrap(); let p = Person::try_from("Mark,twenty").unwrap();
} }
} }

View File

@ -2,16 +2,13 @@
// Please note that the `as` operator is not only used when type casting. // Please note that the `as` operator is not only used when type casting.
// It also helps with renaming imports. // It also helps with renaming imports.
// I AM NOT DONE
// The goal is to make sure that the division does not fail to compile // The goal is to make sure that the division does not fail to compile
fn average(values: &[f64]) -> f64 { fn average(values: &[f64]) -> f64 {
let total = values let total = values.iter().fold(0.0, |a, b| a + *b);
.iter() total / values.len() as f64
.fold(0.0, |a, b| a + b);
total / values.len()
} }
fn main() { fn main() {
let values = [3.5, 0.3, 13.0, 11.7]; let values = [3.5, 0.3, 13.0, 11.7];
println!("{}", average(&values)); println!("{}", average(&values));
} }

View File

@ -1,10 +1,9 @@
// This shopping list program isn't compiling! // This shopping list program isn't compiling!
// Use your knowledge of generics to fix it. // Use your knowledge of generics to fix it.
// I AM NOT DONE
fn main() { fn main() {
let mut shopping_list: Vec<?> = Vec::new(); let mut shopping_list: Vec<&str> = Vec::new();
shopping_list.push("milk"); shopping_list.push("milk");
} }

View File

@ -1,13 +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.
// Rewrite it using generics so that it supports wrapping ANY type. // Rewrite it using generics so that it supports wrapping ANY type.
// I AM NOT DONE struct Wrapper<T> {
struct Wrapper<u32> { value: T,
value: u32
} }
impl<u32> Wrapper<u32> { impl<T> Wrapper<T> {
pub fn new(value: u32) -> Self { pub fn new(value: T) -> Self {
Wrapper { value } Wrapper { value }
} }
} }
@ -18,13 +17,11 @@ mod tests {
#[test] #[test]
fn store_u32_in_wrapper() { fn store_u32_in_wrapper() {
assert_eq!(Wrapper::new(42).value, 42); assert_eq!(Wrapper::new(42).value, 42);
} }
#[test] #[test]
fn store_str_in_wrapper() { fn store_str_in_wrapper() {
// TODO: Delete this assert and uncomment the one below once you have finished the exercise. assert_eq!(Wrapper::new("Foo").value, "Foo");
assert!(false);
// assert_eq!(Wrapper::new("Foo").value, "Foo");
} }
} }

View File

@ -1,21 +1,24 @@
// An imaginary magical school has a new report card generation system written in rust! // An imaginary magical school has a new report card generation system written in rust!
// Currently the system only supports creating report cards where the student's grade // Currently the system only supports creating report cards where the student's grade
// is represented numerically (e.g. 1.0 -> 5.5). However, the school also issues alphabetical grades // is represented numerically (e.g. 1.0 -> 5.5). However, the school also issues alphabetical grades
// (A+ -> F-) and needs to be able to print both types of report card! // (A+ -> F-) and needs to be able to print both types of report card!
// Make the necessary code changes to support alphabetical report cards, thereby making the second // Make the necessary code changes to support alphabetical report cards, thereby making the second
// test pass. // test pass.
use std::fmt::Display;
// I AM NOT DONE pub struct ReportCard<T> {
pub struct ReportCard { pub grade: T,
pub grade: f32,
pub student_name: String, pub student_name: String,
pub student_age: u8, pub student_age: u8,
} }
impl ReportCard { impl<T: Display> ReportCard<T> {
pub fn print(&self) -> String { pub fn print(&self) -> String {
format!("{} ({}) - achieved a grade of {}", &self.student_name, &self.student_age, &self.grade) format!(
"{} ({}) - achieved a grade of {}",
&self.student_name, &self.student_age, &self.grade
)
} }
} }
@ -26,21 +29,27 @@ mod tests {
#[test] #[test]
fn generate_numeric_report_card() { fn generate_numeric_report_card() {
let report_card = ReportCard { let report_card = ReportCard {
grade: 2.1, grade: 2.1,
student_name: "Tom Wriggle".to_string(), student_name: "Tom Wriggle".to_string(),
student_age: 12, student_age: 12,
}; };
assert_eq!(report_card.print(), "Tom Wriggle (12) - achieved a grade of 2.1"); assert_eq!(
report_card.print(),
"Tom Wriggle (12) - achieved a grade of 2.1"
);
} }
#[test] #[test]
fn generate_alphabetic_report_card() { fn generate_alphabetic_report_card() {
// TODO: Make sure to change the grade here after you finish the exercise. // TODO: Make sure to change the grade here after you finish the exercise.
let report_card = ReportCard { let report_card = ReportCard {
grade: 2.1, grade: "A+".to_string(),
student_name: "Gary Plotter".to_string(), student_name: "Gary Plotter".to_string(),
student_age: 11, student_age: 11,
}; };
assert_eq!(report_card.print(), "Gary Plotter (11) - achieved a grade of A+"); assert_eq!(
report_card.print(),
"Gary Plotter (11) - achieved a grade of A+"
);
} }
} }

View File

@ -4,20 +4,21 @@
// somewhere. Try not to create any copies of the `numbers` Vec! // somewhere. Try not to create any copies of the `numbers` Vec!
// Execute `rustlings hint arc1` for hints :) // Execute `rustlings hint arc1` for hints :)
// I AM NOT DONE
use std::sync::Arc; use std::sync::Arc;
use std::thread; use std::thread;
fn main() { fn main() {
let numbers: Vec<_> = (0..100u32).collect(); let numbers: Vec<_> = (0..100u32).collect();
let shared_numbers = // TODO let shared_numbers = Arc::new(numbers);
let mut joinhandles = Vec::new(); let mut joinhandles = Vec::new();
for offset in 0..8 { for offset in 0..8 {
let child_numbers = shared_numbers.clone();
joinhandles.push(thread::spawn(move || { joinhandles.push(thread::spawn(move || {
let mut i = offset; let mut i = offset;
let mut sum = 0; let mut sum = 0;
while i < child_numbers.len() { while i < child_numbers.len() {
sum += child_numbers[i]; sum += child_numbers[i];
i += 5; i += 5;

View File

@ -5,13 +5,14 @@
// Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string // Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string
// As always, there are hints if you execute `rustlings hint iterators2`! // As always, there are hints if you execute `rustlings hint iterators2`!
// I AM NOT DONE
use std::str::Chars;
pub fn capitalize_first(input: &str) -> String { pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars(); let mut c: Chars = input.chars();
match c.next() { match c.next() {
None => String::new(), None => String::new(),
Some(first) => first.collect::<String>() + c.as_str(), Some(first) => first.to_uppercase().collect::<String>() + c.as_str(),
} }
} }
@ -35,14 +36,14 @@ mod tests {
#[test] #[test]
fn test_iterate_string_vec() { fn test_iterate_string_vec() {
let words = vec!["hello", "world"]; let words = vec!["hello", "world"];
let capitalized_words: Vec<String> = // TODO let capitalized_words: Vec<String> = words.iter().map(|&c| capitalize_first(c)).collect();
assert_eq!(capitalized_words, ["Hello", "World"]); assert_eq!(capitalized_words, ["Hello", "World"]);
} }
#[test] #[test]
fn test_iterate_into_string() { fn test_iterate_into_string() {
let words = vec!["hello", " ", "world"]; let words = vec!["hello", " ", "world"];
let capitalized_words = // TODO let capitalized_words = words.iter().map(|&c| capitalize_first(c)).collect::<String>();
assert_eq!(capitalized_words, "Hello World"); assert_eq!(capitalized_words, "Hello World");
} }
} }

View File

@ -7,7 +7,6 @@
// Execute `rustlings hint iterators3` to get some hints! // Execute `rustlings hint iterators3` to get some hints!
// Have fun :-) // Have fun :-)
// I AM NOT DONE
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum DivisionError { pub enum DivisionError {
@ -24,7 +23,18 @@ pub struct NotDivisibleError {
// This function should calculate `a` divided by `b` if `a` is // This function should calculate `a` divided by `b` if `a` is
// evenly divisible by b. // evenly divisible by b.
// Otherwise, it should return a suitable error. // Otherwise, it should return a suitable error.
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {} pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
if b == 0 {
Err(DivisionError::DivideByZero)
} else if a % b != 0 {
Err(DivisionError::NotDivisible(NotDivisibleError {
dividend: a,
divisor: b,
}))
} else {
Ok(a / b)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -42,7 +52,7 @@ mod tests {
divide(81, 6), divide(81, 6),
Err(DivisionError::NotDivisible(NotDivisibleError { Err(DivisionError::NotDivisible(NotDivisibleError {
dividend: 81, dividend: 81,
divisor: 6 divisor: 6,
})) }))
); );
} }
@ -58,12 +68,12 @@ mod tests {
} }
// Iterator exercises using your `divide` function // Iterator exercises using your `divide` function
/*
#[test] #[test]
fn result_with_list() { fn result_with_list() {
let numbers = vec![27, 297, 38502, 81]; let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27)); let division_results = numbers.into_iter().map(|n| divide(n, 27));
let x //... Fill in here! let x = division_results.collect::<Result<Vec<i32>, _>>();
assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])"); assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])");
} }
@ -71,8 +81,8 @@ mod tests {
fn list_of_results() { fn list_of_results() {
let numbers = vec![27, 297, 38502, 81]; let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27)); let division_results = numbers.into_iter().map(|n| divide(n, 27));
let x //... Fill in here! let x = division_results.collect::<Vec<Result<i32, DivisionError>>>();
assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]"); assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]");
} }
*/
} }

View File

@ -1,6 +1,5 @@
// iterators4.rs // iterators4.rs
// I AM NOT DONE
pub fn factorial(num: u64) -> u64 { pub fn factorial(num: u64) -> u64 {
// Complete this function to return factorial of num // Complete this function to return factorial of num
@ -12,6 +11,11 @@ pub fn factorial(num: u64) -> u64 {
// For the most fun don't use: // For the most fun don't use:
// - recursion // - recursion
// Execute `rustlings hint iterators4` for hints. // Execute `rustlings hint iterators4` for hints.
match num {
1 => 1,
n => n * factorial(n - 1)
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -5,9 +5,10 @@
// of "waiting..." and the program ends without timing out when running, // of "waiting..." and the program ends without timing out when running,
// you've got it :) // you've got it :)
// I AM NOT DONE
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
@ -16,16 +17,18 @@ struct JobStatus {
} }
fn main() { fn main() {
let status = Arc::new(JobStatus { jobs_completed: 0 }); let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = status.clone(); let status_shared = status.clone();
thread::spawn(move || { thread::spawn(move || {
for _ in 0..10 { for _ in 0..100 {
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(25));
status_shared.jobs_completed += 1; let mut sharedJobStatus: MutexGuard<JobStatus> = status_shared.lock().unwrap();
let curr_jobs_completed: u32 = sharedJobStatus.jobs_completed as u32;
*sharedJobStatus = JobStatus { jobs_completed: curr_jobs_completed + 1 };
} }
}); });
while status.jobs_completed < 10 { while status.lock().unwrap().jobs_completed < 20 {
println!("waiting... "); println!("waiting... {}", status.lock().unwrap().jobs_completed);
thread::sleep(Duration::from_millis(500)); thread::sleep(Duration::from_millis(25));
} }
} }

View File

@ -8,14 +8,15 @@
// which appends "Bar" to any object // which appends "Bar" to any object
// implementing this trait. // implementing this trait.
// I AM NOT DONE
trait AppendBar { trait AppendBar {
fn append_bar(self) -> Self; fn append_bar(self) -> Self;
} }
impl AppendBar for String { impl AppendBar for String {
//Add your code here
fn append_bar(self) -> Self {
self + "Bar"
}
} }
fn main() { fn main() {
@ -41,4 +42,4 @@ mod tests {
); );
} }
} }

View File

@ -1,25 +1,26 @@
// traits2.rs // traits2.rs
// //
// Your task is to implement the trait // Your task is to implement the trait
// `AppendBar' for a vector of strings. // `AppendBar' for a vector of strings.
// //
// To implement this trait, consider for // To implement this trait, consider for
// a moment what it means to 'append "Bar"' // a moment what it means to 'append "Bar"'
// to a vector of strings. // to a vector of strings.
// //
// No boiler plate code this time, // No boiler plate code this time,
// you can do this! // you can do this!
// I AM NOT DONE
trait AppendBar { trait AppendBar {
fn append_bar(self) -> Self; fn append_bar(self) -> Self;
} }
//TODO: Add your code here impl AppendBar for Vec<String> {
fn append_bar(mut self) -> Self {
self.push("Bar".to_string());
self
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -31,5 +32,4 @@ mod tests {
assert_eq!(foo.pop().unwrap(), String::from("Bar")); assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo")); assert_eq!(foo.pop().unwrap(), String::from("Foo"));
} }
} }