1. ```rust trait Hello { fn say_hi(&self) -> String { String::from("hi") } fn say_something(&self) -> String; } struct Student {} impl Hello for Student { fn say_something(&self) -> String { String::from("I'm a good student") } } struct Teacher {} impl Hello for Teacher { fn say_hi(&self) -> String { String::from("Hi, I'm your new teacher") } fn say_something(&self) -> String { String::from("I'm not a bad teacher") } } fn main() { let s = Student {}; assert_eq!(s.say_hi(), "hi"); assert_eq!(s.say_something(), "I'm a good student"); let t = Teacher {}; assert_eq!(t.say_hi(), "Hi, I'm your new teacher"); assert_eq!(t.say_something(), "I'm not a bad teacher"); } ``` 2. ```rust // `Centimeters`, a tuple struct that can be compared #[derive(PartialEq, PartialOrd)] struct Centimeters(f64); // `Inches`, a tuple struct that can be printed #[derive(Debug)] struct Inches(i32); impl Inches { fn to_centimeters(&self) -> Centimeters { let &Inches(inches) = self; Centimeters(inches as f64 * 2.54) } } // Add some attributes to make the code work // DON'T modify other codes #[derive(Debug,PartialEq,PartialOrd)] struct Seconds(i32); fn main() { let _one_second = Seconds(1); println!("One second looks like: {:?}", _one_second); let _this_is_true = (_one_second == _one_second); let _this_is_true = (_one_second > _one_second); let foot = Inches(12); println!("One foot equals {:?}", foot); let meter = Centimeters(100.0); let cmp = if foot.to_centimeters() < meter { "smaller" } else { "bigger" }; println!("One foot is {} than one meter.", cmp); } ``` 3. ```rust use std::ops; // implement fn multiply to make the code work // As mentiond above, `+` needs `T` to implement `std::ops::Add` Trait // so, what about `*` ? You can find the answer here: https://doc.rust-lang.org/core/ops/ fn multiply>(x: T, y: T) -> T { x * y } fn main() { assert_eq!(6, multiply(2u8, 3u8)); assert_eq!(5.0, multiply(1.0, 5.0)); } ``` 4. ```rust use std::ops; struct Foo; struct Bar; #[derive(PartialEq, Debug)] struct FooBar; #[derive(PartialEq, Debug)] struct BarFoo; // The `std::ops::Add` trait is used to specify the functionality of `+`. // Here, we make `Add` - the trait for addition with a RHS of type `Bar`. // The following block implements the operation: Foo + Bar = FooBar impl ops::Add for Foo { type Output = FooBar; fn add(self, _rhs: Bar) -> FooBar { FooBar } } impl ops::Sub for Foo { type Output = BarFoo; fn sub(self, _rhs: Bar) -> BarFoo { BarFoo } } fn main() { // DON'T modify the below code // you need to derive some trait for FooBar to make it comparable assert_eq!(Foo + Bar, FooBar); assert_eq!(Foo - Bar, BarFoo); } ``` 5. ```rust // implement `fn summary` to make the code work // fix the errors without removing any code line trait Summary { fn summarize(&self) -> String; } #[derive(Debug)] struct Post { title: String, author: String, content: String, } impl Summary for Post { fn summarize(&self) -> String { format!("The author of post {} is {}", self.title, self.author) } } #[derive(Debug)] struct Weibo { username: String, content: String, } impl Summary for Weibo { fn summarize(&self) -> String { format!("{} published a weibo {}", self.username, self.content) } } fn main() { let post = Post { title: "Popular Rust".to_string(), author: "Sunface".to_string(), content: "Rust is awesome!".to_string(), }; let weibo = Weibo { username: "sunface".to_string(), content: "Weibo seems to be worse than Tweet".to_string(), }; summary(&post); summary(&weibo); println!("{:?}", post); println!("{:?}", weibo); } fn summary(t: &impl Summary) { let _ = t.summarize(); } ``` 6. ```rust struct Sheep {} struct Cow {} trait Animal { fn noise(&self) -> String; } impl Animal for Sheep { fn noise(&self) -> String { "baaaaah!".to_string() } } impl Animal for Cow { fn noise(&self) -> String { "moooooo!".to_string() } } // Returns some struct that implements Animal, but we don't know which one at compile time. // FIX the erros here, you can make a fake random, or you can use trait object fn random_animal(random_number: f64) -> impl Animal { if random_number < 0.5 { Sheep {} } else { Sheep {} } } fn main() { let random_number = 0.234; let animal = random_animal(random_number); println!("You've randomly chosen an animal, and it says {}", animal.noise()); } ``` ```rust struct Sheep {} struct Cow {} trait Animal { fn noise(&self) -> String; } impl Animal for Sheep { fn noise(&self) -> String { "baaaaah!".to_string() } } impl Animal for Cow { fn noise(&self) -> String { "moooooo!".to_string() } } // Returns some struct that implements Animal, but we don't know which one at compile time. // FIX the erros here, you can make a fake random, or you can use trait object fn random_animal(random_number: f64) -> Box { if random_number < 0.5 { Box::new(Sheep {}) } else { Box::new(Cow{}) } } fn main() { let random_number = 0.234; let animal = random_animal(random_number); println!("You've randomly chosen an animal, and it says {}", animal.noise()); } ``` 7. ```rust fn main() { assert_eq!(sum(1, 2), 3); assert_eq!(sum(1.0, 2.0), 3.0); } fn sum>(x: T, y: T) -> T { x + y } ``` ```rust fn main() { assert_eq!(sum(1, 2), 3); assert_eq!(sum(1.0, 2.0), 3.0); } fn sum(x: T, y: T) -> T where T: std::ops::Add, { x + y } ``` 8. ```rust struct Pair { x: T, y: T, } impl Pair { fn new(x: T, y: T) -> Self { Self { x, y, } } } impl Pair { fn cmp_display(&self) { if self.x >= self.y { println!("The largest member is x = {:?}", self.x); } else { println!("The largest member is y = {:?}", self.y); } } } #[derive(Debug, PartialEq, PartialOrd)] struct Unit(i32); fn main() { let pair = Pair{ x: Unit(1), y: Unit(3) }; pair.cmp_display(); } ``` 9. ```rust fn example1() { // `T: Trait` is the commonly used way // `T: Fn(u32) -> u32` specifies that we can only pass a closure to `T` struct Cacher u32> { calculation: T, value: Option, } impl u32> Cacher { fn new(calculation: T) -> Cacher { Cacher { calculation, value: None, } } fn value(&mut self, arg: u32) -> u32 { match self.value { Some(v) => v, None => { let v = (self.calculation)(arg); self.value = Some(v); v }, } } } let mut cacher = Cacher::new(|x| x+1); assert_eq!(cacher.value(10), 11); assert_eq!(cacher.value(15), 11); } fn example2() { // We can also use `where` to constrain `T` struct Cacher where T: Fn(u32) -> u32, { calculation: T, value: Option, } impl Cacher where T: Fn(u32) -> u32, { fn new(calculation: T) -> Cacher { Cacher { calculation, value: None, } } fn value(&mut self, arg: u32) -> u32 { match self.value { Some(v) => v, None => { let v = (self.calculation)(arg); self.value = Some(v); v }, } } } let mut cacher = Cacher::new(|x| x+1); assert_eq!(cacher.value(20), 21); assert_eq!(cacher.value(25), 21); } fn main() { example1(); example2(); } ```