progress through generics and traits
This commit is contained in:
parent
7e6588f6f0
commit
3fcd3d8e03
17 changed files with 309 additions and 37 deletions
|
@ -1,6 +1,6 @@
|
||||||
DON'T EDIT THIS FILE!
|
DON'T EDIT THIS FILE!
|
||||||
|
|
||||||
generics1
|
lifetimes1
|
||||||
|
|
||||||
intro1
|
intro1
|
||||||
intro2
|
intro2
|
||||||
|
@ -57,4 +57,12 @@ errors2
|
||||||
errors3
|
errors3
|
||||||
errors4
|
errors4
|
||||||
errors5
|
errors5
|
||||||
errors6
|
errors6
|
||||||
|
generics1
|
||||||
|
generics2
|
||||||
|
traits1
|
||||||
|
traits2
|
||||||
|
traits3
|
||||||
|
traits4
|
||||||
|
traits5
|
||||||
|
quiz3
|
|
@ -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;
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,10 @@ trait AppendBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppendBar for String {
|
impl AppendBar for String {
|
||||||
// TODO: Implement `AppendBar` for the type `String`.
|
fn append_bar(mut self) -> Self {
|
||||||
|
self.push_str("Bar");
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -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(String::from("Bar"));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// You can optionally experiment here.
|
// You can optionally experiment here.
|
||||||
|
|
|
@ -5,7 +5,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 {
|
||||||
|
return String::from("Default license")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SomeSoftware {
|
struct SomeSoftware {
|
||||||
|
|
|
@ -11,7 +11,8 @@ 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<T, F>(software1: T, software2: F) -> bool
|
||||||
|
where T: Licensed, F: Licensed{
|
||||||
software1.licensing_info() == software2.licensing_info()
|
software1.licensing_info() == software2.licensing_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ 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<T>(item: T) -> bool
|
||||||
|
where T: OtherTrait + SomeTrait{
|
||||||
item.some_function() && item.other_function()
|
item.some_function() && item.other_function()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,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<T> where T: Display {
|
||||||
grade: f32,
|
grade: T,
|
||||||
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 <T: Display>ReportCard<T> {
|
||||||
fn print(&self) -> String {
|
fn print(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} ({}) - achieved a grade of {}",
|
"{} ({}) - achieved a grade of {}",
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
|
// `Vec<T>` 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() {
|
fn main() {
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// `u8` and `i8` can both be converted to `i16`.
|
||||||
// It will be automatically filled after you finish the exercise.
|
let mut numbers: Vec<i16> = 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:?}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,28 @@
|
||||||
fn main() {
|
struct Wrapper<T> {
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
value: T,
|
||||||
// It will be automatically filled after you finish the exercise.
|
}
|
||||||
|
|
||||||
|
impl<T> Wrapper<T> {
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,32 @@
|
||||||
fn main() {
|
// The trait `AppendBar` has only one function which appends "Bar" to any object
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// implementing this trait.
|
||||||
// It will be automatically filled after you finish the exercise.
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,27 @@
|
||||||
fn main() {
|
trait AppendBar {
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
fn append_bar(self) -> Self;
|
||||||
// It will be automatically filled after you finish the exercise.
|
}
|
||||||
|
|
||||||
|
impl AppendBar for Vec<String> {
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,38 @@
|
||||||
fn main() {
|
#![allow(dead_code)]
|
||||||
// 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 {
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,35 @@
|
||||||
fn main() {
|
trait Licensed {
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
fn licensing_info(&self) -> String {
|
||||||
// It will be automatically filled after you finish the exercise.
|
"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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,39 @@
|
||||||
fn main() {
|
trait SomeTrait {
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
fn some_function(&self) -> bool {
|
||||||
// It will be automatically filled after you finish the exercise.
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,65 @@
|
||||||
fn main() {
|
// An imaginary magical school has a new report card generation system written
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// in Rust! Currently, the system only supports creating report cards where the
|
||||||
// It will be automatically filled after you finish the exercise.
|
// 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<T> {
|
||||||
|
// ^^^
|
||||||
|
grade: T,
|
||||||
|
// ^
|
||||||
|
student_name: String,
|
||||||
|
student_age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be able to print the grade, it has to implement the `Display` trait.
|
||||||
|
impl<T: Display> ReportCard<T> {
|
||||||
|
// ^^^^^^^ 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+",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue