diff --git a/.rustlings-state.txt b/.rustlings-state.txt index c3678cb..888d577 100644 --- a/.rustlings-state.txt +++ b/.rustlings-state.txt @@ -1,6 +1,6 @@ DON'T EDIT THIS FILE! -generics1 +lifetimes1 intro1 intro2 @@ -57,4 +57,12 @@ errors2 errors3 errors4 errors5 -errors6 \ No newline at end of file +errors6 +generics1 +generics2 +traits1 +traits2 +traits3 +traits4 +traits5 +quiz3 \ No newline at end of file diff --git a/exercises/14_generics/generics1.rs b/exercises/14_generics/generics1.rs index 87ed990..7e5571f 100644 --- a/exercises/14_generics/generics1.rs +++ b/exercises/14_generics/generics1.rs @@ -6,7 +6,7 @@ fn main() { // TODO: Fix the compiler error by annotating the type of the vector // `Vec`. Choose `T` as some integer type that can be created from // `u8` and `i8`. - let mut numbers = Vec::new(); + let mut numbers: Vec = Vec::new(); // Don't change the lines below. let n1: u8 = 42; diff --git a/exercises/14_generics/generics2.rs b/exercises/14_generics/generics2.rs index 8908725..3029911 100644 --- a/exercises/14_generics/generics2.rs +++ b/exercises/14_generics/generics2.rs @@ -1,12 +1,12 @@ // 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. -struct Wrapper { - value: u32, +struct Wrapper { + value: T, } // TODO: Adapt the struct's implementation to be generic over the wrapped value. -impl Wrapper { - fn new(value: u32) -> Self { +impl Wrapper { + fn new(value: T) -> Self { Wrapper { value } } } diff --git a/exercises/15_traits/traits1.rs b/exercises/15_traits/traits1.rs index 85be17e..c643b6b 100644 --- a/exercises/15_traits/traits1.rs +++ b/exercises/15_traits/traits1.rs @@ -5,7 +5,10 @@ trait AppendBar { } impl AppendBar for String { - // TODO: Implement `AppendBar` for the type `String`. + fn append_bar(mut self) -> Self { + self.push_str("Bar"); + self + } } fn main() { diff --git a/exercises/15_traits/traits2.rs b/exercises/15_traits/traits2.rs index d724dc2..2c110d7 100644 --- a/exercises/15_traits/traits2.rs +++ b/exercises/15_traits/traits2.rs @@ -4,6 +4,12 @@ trait AppendBar { // TODO: Implement the trait `AppendBar` for a vector of strings. // `append_bar` should push the string "Bar" into the vector. +impl AppendBar for Vec { + fn append_bar(mut self) -> Self { + self.push(String::from("Bar")); + self + } +} fn main() { // You can optionally experiment here. diff --git a/exercises/15_traits/traits3.rs b/exercises/15_traits/traits3.rs index 2e8969e..10237ab 100644 --- a/exercises/15_traits/traits3.rs +++ b/exercises/15_traits/traits3.rs @@ -5,7 +5,9 @@ trait Licensed { // implementors like the two structs below can share that default behavior // without repeating the function. // The default license information should be the string "Default license". - fn licensing_info(&self) -> String; + fn licensing_info(&self) -> String { + return String::from("Default license") + } } struct SomeSoftware { diff --git a/exercises/15_traits/traits4.rs b/exercises/15_traits/traits4.rs index 80092a6..b6e4cce 100644 --- a/exercises/15_traits/traits4.rs +++ b/exercises/15_traits/traits4.rs @@ -11,7 +11,8 @@ impl Licensed for SomeSoftware {} impl Licensed for OtherSoftware {} // 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: T, software2: F) -> bool + where T: Licensed, F: Licensed{ software1.licensing_info() == software2.licensing_info() } diff --git a/exercises/15_traits/traits5.rs b/exercises/15_traits/traits5.rs index 5b356ac..3319e4e 100644 --- a/exercises/15_traits/traits5.rs +++ b/exercises/15_traits/traits5.rs @@ -19,7 +19,8 @@ impl SomeTrait for OtherStruct {} impl OtherTrait for OtherStruct {} // TODO: Fix the compiler error by only changing the signature of this function. -fn some_func(item: ???) -> bool { +fn some_func(item: T) -> bool + where T: OtherTrait + SomeTrait{ item.some_function() && item.other_function() } diff --git a/exercises/quizzes/quiz3.rs b/exercises/quizzes/quiz3.rs index c877c5f..3cd0028 100644 --- a/exercises/quizzes/quiz3.rs +++ b/exercises/quizzes/quiz3.rs @@ -11,15 +11,17 @@ // Make the necessary code changes in the struct `ReportCard` and the impl // block to support alphabetical report cards in addition to numerical ones. +use std::fmt::Display; + // TODO: Adjust the struct as described above. -struct ReportCard { - grade: f32, +struct ReportCard where T: Display { + grade: T, student_name: String, student_age: u8, } // TODO: Adjust the impl block as described above. -impl ReportCard { +impl ReportCard { fn print(&self) -> String { format!( "{} ({}) - achieved a grade of {}", diff --git a/solutions/14_generics/generics1.rs b/solutions/14_generics/generics1.rs index dcf2377..e2195fd 100644 --- a/solutions/14_generics/generics1.rs +++ b/solutions/14_generics/generics1.rs @@ -1,4 +1,17 @@ +// `Vec` is generic over the type `T`. In most cases, the compiler is able to +// infer `T`, for example after pushing a value with a concrete type to the vector. +// But in this exercise, the compiler needs some help through a type annotation. + fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. + // `u8` and `i8` can both be converted to `i16`. + let mut numbers: Vec = Vec::new(); + // ^^^^^^^^^^ added + + // Don't change the lines below. + let n1: u8 = 42; + numbers.push(n1.into()); + let n2: i8 = -1; + numbers.push(n2.into()); + + println!("{numbers:?}"); } diff --git a/solutions/14_generics/generics2.rs b/solutions/14_generics/generics2.rs index dcf2377..14f3f7a 100644 --- a/solutions/14_generics/generics2.rs +++ b/solutions/14_generics/generics2.rs @@ -1,4 +1,28 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +struct Wrapper { + value: T, +} + +impl Wrapper { + fn new(value: T) -> Self { + Wrapper { value } + } +} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn store_u32_in_wrapper() { + assert_eq!(Wrapper::new(42).value, 42); + } + + #[test] + fn store_str_in_wrapper() { + assert_eq!(Wrapper::new("Foo").value, "Foo"); + } } diff --git a/solutions/15_traits/traits1.rs b/solutions/15_traits/traits1.rs index dcf2377..790873f 100644 --- a/solutions/15_traits/traits1.rs +++ b/solutions/15_traits/traits1.rs @@ -1,4 +1,32 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +// The trait `AppendBar` has only one function which appends "Bar" to any object +// implementing this trait. +trait AppendBar { + fn append_bar(self) -> Self; +} + +impl AppendBar for String { + fn append_bar(self) -> Self { + self + "Bar" + } +} + +fn main() { + let s = String::from("Foo"); + let s = s.append_bar(); + println!("s: {s}"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_foo_bar() { + assert_eq!(String::from("Foo").append_bar(), "FooBar"); + } + + #[test] + fn is_bar_bar() { + assert_eq!(String::from("").append_bar().append_bar(), "BarBar"); + } } diff --git a/solutions/15_traits/traits2.rs b/solutions/15_traits/traits2.rs index dcf2377..0db93e0 100644 --- a/solutions/15_traits/traits2.rs +++ b/solutions/15_traits/traits2.rs @@ -1,4 +1,27 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +trait AppendBar { + fn append_bar(self) -> Self; +} + +impl AppendBar for Vec { + fn append_bar(mut self) -> Self { + // ^^^ this is important + self.push(String::from("Bar")); + self + } +} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_vec_pop_eq_bar() { + let mut foo = vec![String::from("Foo")].append_bar(); + assert_eq!(foo.pop().unwrap(), "Bar"); + assert_eq!(foo.pop().unwrap(), "Foo"); + } } diff --git a/solutions/15_traits/traits3.rs b/solutions/15_traits/traits3.rs index dcf2377..747d919 100644 --- a/solutions/15_traits/traits3.rs +++ b/solutions/15_traits/traits3.rs @@ -1,4 +1,38 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +#![allow(dead_code)] + +trait Licensed { + fn licensing_info(&self) -> String { + "Default license".to_string() + } +} + +struct SomeSoftware { + version_number: i32, +} + +struct OtherSoftware { + version_number: String, +} + +impl Licensed for SomeSoftware {} +impl Licensed for OtherSoftware {} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_licensing_info_the_same() { + let licensing_info = "Default license"; + let some_software = SomeSoftware { version_number: 1 }; + let other_software = OtherSoftware { + version_number: "v2.0.0".to_string(), + }; + assert_eq!(some_software.licensing_info(), licensing_info); + assert_eq!(other_software.licensing_info(), licensing_info); + } } diff --git a/solutions/15_traits/traits4.rs b/solutions/15_traits/traits4.rs index dcf2377..3675b8d 100644 --- a/solutions/15_traits/traits4.rs +++ b/solutions/15_traits/traits4.rs @@ -1,4 +1,35 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +trait Licensed { + fn licensing_info(&self) -> String { + "Default license".to_string() + } +} + +struct SomeSoftware; +struct OtherSoftware; + +impl Licensed for SomeSoftware {} +impl Licensed for OtherSoftware {} + +fn compare_license_types(software1: impl Licensed, software2: impl Licensed) -> bool { + // ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ + software1.licensing_info() == software2.licensing_info() +} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn compare_license_information() { + assert!(compare_license_types(SomeSoftware, OtherSoftware)); + } + + #[test] + fn compare_license_information_backwards() { + assert!(compare_license_types(OtherSoftware, SomeSoftware)); + } } diff --git a/solutions/15_traits/traits5.rs b/solutions/15_traits/traits5.rs index dcf2377..1fb426a 100644 --- a/solutions/15_traits/traits5.rs +++ b/solutions/15_traits/traits5.rs @@ -1,4 +1,39 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +trait SomeTrait { + fn some_function(&self) -> bool { + true + } +} + +trait OtherTrait { + fn other_function(&self) -> bool { + true + } +} + +struct SomeStruct; +impl SomeTrait for SomeStruct {} +impl OtherTrait for SomeStruct {} + +struct OtherStruct; +impl SomeTrait for OtherStruct {} +impl OtherTrait for OtherStruct {} + +fn some_func(item: impl SomeTrait + OtherTrait) -> bool { + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + item.some_function() && item.other_function() +} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_some_func() { + assert!(some_func(SomeStruct)); + assert!(some_func(OtherStruct)); + } } diff --git a/solutions/quizzes/quiz3.rs b/solutions/quizzes/quiz3.rs index dcf2377..7b91278 100644 --- a/solutions/quizzes/quiz3.rs +++ b/solutions/quizzes/quiz3.rs @@ -1,4 +1,65 @@ -fn main() { - // DON'T EDIT THIS SOLUTION FILE! - // It will be automatically filled after you finish the exercise. +// 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 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 in the struct `ReportCard` and the impl +// block to support alphabetical report cards in addition to numerical ones. + +use std::fmt::Display; + +// Make the struct generic over `T`. +struct ReportCard { + // ^^^ + grade: T, + // ^ + student_name: String, + student_age: u8, +} + +// To be able to print the grade, it has to implement the `Display` trait. +impl ReportCard { + // ^^^^^^^ require that `T` implements `Display`. + fn print(&self) -> String { + format!( + "{} ({}) - achieved a grade of {}", + &self.student_name, &self.student_age, &self.grade, + ) + } +} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn generate_numeric_report_card() { + let report_card = ReportCard { + 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", + ); + } + + #[test] + fn generate_alphabetic_report_card() { + let report_card = ReportCard { + grade: "A+", + student_name: "Gary Plotter".to_string(), + student_age: 11, + }; + assert_eq!( + report_card.print(), + "Gary Plotter (11) - achieved a grade of A+", + ); + } }