Finish exercises
This commit is contained in:
parent
58fc67525b
commit
9d46b94f9f
exercises
conversions
generics
standard_library_types
threads
traits
|
@ -2,16 +2,15 @@
|
|||
// 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.
|
||||
|
||||
// I AM NOT DONE
|
||||
// Obtain the number of bytes (not characters) in the given argument
|
||||
// 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()
|
||||
}
|
||||
|
||||
// Obtain the number of characters (not bytes) in the given argument
|
||||
// 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()
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ impl Default for Person {
|
|||
}
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// Your task is to complete this implementation
|
||||
// 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`
|
||||
|
@ -34,6 +33,18 @@ impl Default for Person {
|
|||
// Otherwise, then return an instantiated Person onject with the results
|
||||
impl From<&str> for 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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
// Test that the default person is 30 year old John
|
||||
|
@ -56,6 +68,7 @@ mod tests {
|
|||
assert_eq!(dp.name, "John");
|
||||
assert_eq!(dp.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_convert() {
|
||||
// Test that John is returned when bad string is provided
|
||||
|
@ -63,6 +76,7 @@ mod tests {
|
|||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_convert() {
|
||||
// Test that "Mark,20" works
|
||||
|
@ -70,6 +84,7 @@ mod tests {
|
|||
assert_eq!(p.name, "Mark");
|
||||
assert_eq!(p.age, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_age() {
|
||||
// Test that "Mark.twenty" will return the default person due to an error in parsing age
|
||||
|
|
|
@ -10,7 +10,6 @@ struct Person {
|
|||
age: usize,
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// Steps:
|
||||
// 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
|
||||
|
@ -21,6 +20,18 @@ struct Person {
|
|||
impl FromStr for Person {
|
||||
type Err = String;
|
||||
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() {
|
||||
"John".parse::<Person>().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Basically, this is the same as From. The main difference is that this should return a Result type
|
||||
// instead of the target type itself.
|
||||
// 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)]
|
||||
struct Person {
|
||||
|
@ -10,7 +10,6 @@ struct Person {
|
|||
age: usize,
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// Your task is to complete this implementation
|
||||
// in order for the line `let p = Person::try_from("Mark,20")` to compile
|
||||
// and return an Ok result of inner type Person.
|
||||
|
@ -28,6 +27,18 @@ struct Person {
|
|||
impl TryFrom<&str> for Person {
|
||||
type Error = String;
|
||||
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() {
|
||||
let p = Person::try_from("Mark,twenty").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,13 @@
|
|||
// Please note that the `as` operator is not only used when type casting.
|
||||
// It also helps with renaming imports.
|
||||
|
||||
// I AM NOT DONE
|
||||
// The goal is to make sure that the division does not fail to compile
|
||||
fn average(values: &[f64]) -> f64 {
|
||||
let total = values
|
||||
.iter()
|
||||
.fold(0.0, |a, b| a + b);
|
||||
total / values.len()
|
||||
let total = values.iter().fold(0.0, |a, b| a + *b);
|
||||
total / values.len() as f64
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let values = [3.5, 0.3, 13.0, 11.7];
|
||||
println!("{}", average(&values));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
// This shopping list program isn't compiling!
|
||||
// Use your knowledge of generics to fix it.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut shopping_list: Vec<?> = Vec::new();
|
||||
let mut shopping_list: Vec<&str> = Vec::new();
|
||||
shopping_list.push("milk");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// This powerful wrapper provides the ability to store a positive integer value.
|
||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||
|
||||
// I AM NOT DONE
|
||||
struct Wrapper<u32> {
|
||||
value: u32
|
||||
struct Wrapper<T> {
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<u32> Wrapper<u32> {
|
||||
pub fn new(value: u32) -> Self {
|
||||
impl<T> Wrapper<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Wrapper { value }
|
||||
}
|
||||
}
|
||||
|
@ -18,13 +17,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn store_u32_in_wrapper() {
|
||||
assert_eq!(Wrapper::new(42).value, 42);
|
||||
assert_eq!(Wrapper::new(42).value, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_str_in_wrapper() {
|
||||
// TODO: Delete this assert and uncomment the one below once you have finished the exercise.
|
||||
assert!(false);
|
||||
// assert_eq!(Wrapper::new("Foo").value, "Foo");
|
||||
assert_eq!(Wrapper::new("Foo").value, "Foo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
// 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
|
||||
// (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
|
||||
// test pass.
|
||||
use std::fmt::Display;
|
||||
|
||||
// I AM NOT DONE
|
||||
pub struct ReportCard {
|
||||
pub grade: f32,
|
||||
pub struct ReportCard<T> {
|
||||
pub grade: T,
|
||||
pub student_name: String,
|
||||
pub student_age: u8,
|
||||
}
|
||||
|
||||
impl ReportCard {
|
||||
impl<T: Display> ReportCard<T> {
|
||||
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]
|
||||
fn generate_numeric_report_card() {
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Tom Wriggle".to_string(),
|
||||
grade: 2.1,
|
||||
student_name: "Tom Wriggle".to_string(),
|
||||
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]
|
||||
fn generate_alphabetic_report_card() {
|
||||
// TODO: Make sure to change the grade here after you finish the exercise.
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Gary Plotter".to_string(),
|
||||
grade: "A+".to_string(),
|
||||
student_name: "Gary Plotter".to_string(),
|
||||
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+"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,20 +4,21 @@
|
|||
// somewhere. Try not to create any copies of the `numbers` Vec!
|
||||
// Execute `rustlings hint arc1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let numbers: Vec<_> = (0..100u32).collect();
|
||||
let shared_numbers = // TODO
|
||||
let shared_numbers = Arc::new(numbers);
|
||||
let mut joinhandles = Vec::new();
|
||||
|
||||
for offset in 0..8 {
|
||||
let child_numbers = shared_numbers.clone();
|
||||
|
||||
joinhandles.push(thread::spawn(move || {
|
||||
let mut i = offset;
|
||||
let mut sum = 0;
|
||||
|
||||
while i < child_numbers.len() {
|
||||
sum += child_numbers[i];
|
||||
i += 5;
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
// 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`!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::str::Chars;
|
||||
|
||||
pub fn capitalize_first(input: &str) -> String {
|
||||
let mut c = input.chars();
|
||||
let mut c: Chars = input.chars();
|
||||
match c.next() {
|
||||
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]
|
||||
fn test_iterate_string_vec() {
|
||||
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"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate_into_string() {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// Execute `rustlings hint iterators3` to get some hints!
|
||||
// Have fun :-)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DivisionError {
|
||||
|
@ -24,7 +23,18 @@ pub struct NotDivisibleError {
|
|||
// This function should calculate `a` divided by `b` if `a` is
|
||||
// evenly divisible by b.
|
||||
// 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)]
|
||||
mod tests {
|
||||
|
@ -42,7 +52,7 @@ mod tests {
|
|||
divide(81, 6),
|
||||
Err(DivisionError::NotDivisible(NotDivisibleError {
|
||||
dividend: 81,
|
||||
divisor: 6
|
||||
divisor: 6,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
@ -58,12 +68,12 @@ mod tests {
|
|||
}
|
||||
|
||||
// Iterator exercises using your `divide` function
|
||||
/*
|
||||
|
||||
#[test]
|
||||
fn result_with_list() {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
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])");
|
||||
}
|
||||
|
||||
|
@ -71,8 +81,8 @@ mod tests {
|
|||
fn list_of_results() {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
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)]");
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// iterators4.rs
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn factorial(num: u64) -> u64 {
|
||||
// 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:
|
||||
// - recursion
|
||||
// Execute `rustlings hint iterators4` for hints.
|
||||
|
||||
match num {
|
||||
1 => 1,
|
||||
n => n * factorial(n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
// of "waiting..." and the program ends without timing out when running,
|
||||
// you've got it :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::MutexGuard;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -16,16 +17,18 @@ struct JobStatus {
|
|||
}
|
||||
|
||||
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();
|
||||
thread::spawn(move || {
|
||||
for _ in 0..10 {
|
||||
thread::sleep(Duration::from_millis(250));
|
||||
status_shared.jobs_completed += 1;
|
||||
for _ in 0..100 {
|
||||
thread::sleep(Duration::from_millis(25));
|
||||
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 {
|
||||
println!("waiting... ");
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
while status.lock().unwrap().jobs_completed < 20 {
|
||||
println!("waiting... {}", status.lock().unwrap().jobs_completed);
|
||||
thread::sleep(Duration::from_millis(25));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
// which appends "Bar" to any object
|
||||
// implementing this trait.
|
||||
|
||||
// I AM NOT DONE
|
||||
trait AppendBar {
|
||||
fn append_bar(self) -> Self;
|
||||
}
|
||||
|
||||
impl AppendBar for String {
|
||||
//Add your code here
|
||||
|
||||
fn append_bar(self) -> Self {
|
||||
self + "Bar"
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -41,4 +42,4 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
// traits2.rs
|
||||
//
|
||||
//
|
||||
// Your task is to implement the trait
|
||||
// `AppendBar' for a vector of strings.
|
||||
//
|
||||
//
|
||||
// To implement this trait, consider for
|
||||
// a moment what it means to 'append "Bar"'
|
||||
// to a vector of strings.
|
||||
//
|
||||
//
|
||||
// No boiler plate code this time,
|
||||
// you can do this!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
trait AppendBar {
|
||||
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)]
|
||||
mod tests {
|
||||
|
@ -31,5 +32,4 @@ mod tests {
|
|||
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
|
||||
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue