mirror of
https://github.com/sunface/rust-by-practice.git
synced 2025-06-23 04:29:41 +00:00
add advanced-trait.md
This commit is contained in:
228
solutions/generics-traits/advanced-trait.md
Normal file
228
solutions/generics-traits/advanced-trait.md
Normal file
@ -0,0 +1,228 @@
|
||||
1.
|
||||
```rust
|
||||
struct Container(i32, i32);
|
||||
|
||||
// A trait which checks if 2 items are stored inside of container.
|
||||
// Also retrieves first or last value.
|
||||
trait Contains {
|
||||
// Define generic types here which methods will be able to utilize.
|
||||
type A;
|
||||
type B;
|
||||
|
||||
fn contains(&self, _: &Self::A, _: &Self::B) -> bool;
|
||||
fn first(&self) -> i32;
|
||||
fn last(&self) -> i32;
|
||||
}
|
||||
|
||||
impl Contains for Container {
|
||||
// Specify what types `A` and `B` are. If the `input` type
|
||||
// is `Container(i32, i32)`, the `output` types are determined
|
||||
// as `i32` and `i32`.
|
||||
type A = i32;
|
||||
type B = i32;
|
||||
|
||||
// `&Self::A` and `&Self::B` are also valid here.
|
||||
fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
|
||||
(&self.0 == number_1) && (&self.1 == number_2)
|
||||
}
|
||||
// Grab the first number.
|
||||
fn first(&self) -> i32 { self.0 }
|
||||
|
||||
// Grab the last number.
|
||||
fn last(&self) -> i32 { self.1 }
|
||||
}
|
||||
|
||||
fn difference<C: Contains>(container: &C) -> i32 {
|
||||
container.last() - container.first()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let number_1 = 3;
|
||||
let number_2 = 10;
|
||||
|
||||
let container = Container(number_1, number_2);
|
||||
|
||||
println!("Does container contain {} and {}: {}",
|
||||
&number_1, &number_2,
|
||||
container.contains(&number_1, &number_2));
|
||||
println!("First number: {}", container.first());
|
||||
println!("Last number: {}", container.last());
|
||||
|
||||
println!("The difference is: {}", difference(&container));
|
||||
}
|
||||
```
|
||||
|
||||
2.
|
||||
```rust
|
||||
impl<T: Sub<Output = T>> Sub<Point<T>> for Point<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Point {
|
||||
x: self.x - other.x,
|
||||
y: self.y - other.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
impl<T: Sub<Output = T>> Sub<Self> for Point<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Point {
|
||||
x: self.x - other.x,
|
||||
y: self.y - other.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
impl<T: Sub<Output = T>> Sub for Point<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Point {
|
||||
x: self.x - other.x,
|
||||
y: self.y - other.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3.
|
||||
```rust
|
||||
trait Pilot {
|
||||
fn fly(&self) -> String;
|
||||
}
|
||||
|
||||
trait Wizard {
|
||||
fn fly(&self) -> String;
|
||||
}
|
||||
|
||||
struct Human;
|
||||
|
||||
impl Pilot for Human {
|
||||
fn fly(&self) -> String {
|
||||
String::from("This is your captain speaking.")
|
||||
}
|
||||
}
|
||||
|
||||
impl Wizard for Human {
|
||||
fn fly(&self) -> String {
|
||||
String::from("Up!")
|
||||
}
|
||||
}
|
||||
|
||||
impl Human {
|
||||
fn fly(&self) -> String {
|
||||
String::from("*waving arms furiously*")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let person = Human;
|
||||
assert_eq!(Pilot::fly(&person), "This is your captain speaking.");
|
||||
assert_eq!(Wizard::fly(&person), "Up!");
|
||||
|
||||
assert_eq!(person.fly(), "*waving arms furiously*");
|
||||
|
||||
println!("Success!")
|
||||
}
|
||||
```
|
||||
|
||||
4.
|
||||
```rust
|
||||
trait Person {
|
||||
fn name(&self) -> String;
|
||||
}
|
||||
|
||||
// Person is a supertrait of Student.
|
||||
// Implementing Student requires you to also impl Person.
|
||||
trait Student: Person {
|
||||
fn university(&self) -> String;
|
||||
}
|
||||
|
||||
trait Programmer {
|
||||
fn fav_language(&self) -> String;
|
||||
}
|
||||
|
||||
// CompSciStudent (computer science student) is a subtrait of both Programmer
|
||||
// and Student. Implementing CompSciStudent requires you to impl both supertraits.
|
||||
trait CompSciStudent: Programmer + Student {
|
||||
fn git_username(&self) -> String;
|
||||
}
|
||||
|
||||
fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String {
|
||||
format!(
|
||||
"My name is {} and I attend {}. My favorite language is {}. My Git username is {}",
|
||||
student.name(),
|
||||
student.university(),
|
||||
student.fav_language(),
|
||||
student.git_username()
|
||||
)
|
||||
}
|
||||
|
||||
struct CSStudent {
|
||||
name: String,
|
||||
university: String,
|
||||
fav_language: String,
|
||||
git_username: String
|
||||
}
|
||||
|
||||
impl Person for CSStudent {
|
||||
fn name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Student for CSStudent {
|
||||
fn university(&self) -> String {
|
||||
self.university.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Programmer for CSStudent {
|
||||
fn fav_language(&self) -> String {
|
||||
self.fav_language.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl CompSciStudent for CSStudent {
|
||||
fn git_username(&self) -> String {
|
||||
self.git_username.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let student = CSStudent {
|
||||
name: "Sunfei".to_string(),
|
||||
university: "XXX".to_string(),
|
||||
fav_language: "Rust".to_string(),
|
||||
git_username: "sunface".to_string()
|
||||
};
|
||||
|
||||
println!("{}", comp_sci_student_greeting(&student));
|
||||
}
|
||||
```
|
||||
|
||||
5.
|
||||
```rust
|
||||
use std::fmt;
|
||||
|
||||
// DEFINE a newtype `Pretty`
|
||||
struct Pretty(String);
|
||||
|
||||
impl fmt::Display for Pretty {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\"{}\"", self.0.clone() + ", world")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let w = Pretty("hello".to_string());
|
||||
println!("w = {}", w);
|
||||
}
|
||||
```
|
Reference in New Issue
Block a user