✅impls经常被用来定义Rust的structs和enums方法
✅ Traits有点儿像OOP语言中的interfaces。它们通常被用来定义必须被提供的功能性。大部分的traits可以为单一类型实现
但是traits也可以包含默认方法实现,在实现类型的时候默认方法可以被重写
1、Impl without traits
struct Player {
first_name: String,
last_name: String,
}
impl Player {
fn full_name(&self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
fn main() {
let player_1 = Player {
first_name: "Rafael".to_string(),
last_name: "Nadal".to_string(),
};
println!("Player 01: {}", player_1.full_name());
}
// ⭐️ Implementation must appear in the same crate as the self type
// And also in Rust, new traits can be implemented for existing types even for types like i8, f64 and etc.
// Same way existing traits can be implemented for new types you are creating.
// But we can not implement existing traits into existing types.
Impls & traits,without default methods
struct Player {
first_name: String,
last_name: String,
}
trait FullName {
fn full_name(&self) -> String;
}
impl FullName for Player {
fn full_name(&self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
fn main() {
let player_2 = Player {
first_name: "Roger".to_string(),
last_name: "Federer".to_string(),
};
println!("Player 02: {}", player_2.full_name());
}
// Other than functions, traits can contain constants and types.
2、Impls, traits & default methods
trait Foo {
fn bar(&self);
fn baz(&self) { println!("We called baz."); }
}
正如你所看到的方法的第一个参数是特殊的,类型是itself。要么是self,&self要么是 &mut self; self如果它是栈上的值,&self如果它是一个参考,&mut self如果它是一个可变的参考
Impls with Associated functions
一些其他的语言支持静态方法。在这种情况下,我们可以直接通过class调用一个函数而不是创建一个对象。在Rust中,我们把它们称为关联函数。我们在从struct中调用他们的时候使用::而不是.
例如:
Person::new("Elon Musk Jr");
struct Player {
first_name: String,
last_name: String,
}
impl Player {
fn new(first_name: String, last_name: String) -> Player {
Player {
first_name : first_name,
last_name : last_name,
}
}
fn full_name(&self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
fn main() {
let player_name = Player::new("Serena".to_string(), "Williams".to_string()).full_name();
println!("Player: {}", player_name);
}
// We have used :: notation for `new()` and . notation for `full_name()`
// Also in here, instead of using new() and full_name() separately as two expressions,
// we can use Method Chaining. ex. `player.add_points(2).get_point_count();`
3、Traits with generics
trait From {
fn from(T) -> Self;
}
impl From for u16 {
//...
}
impl From for u32{
//...
}
// Should specify after the trait name like generic functions
4、Traits inheritance
trait Person {
fn full_name(&self) -> String;
}
trait Employee : Person { // Employee inherits from person trait
fn job_title(&self) -> String;
}
trait ExpatEmployee : Employee + Expat { // ExpatEmployee inherits from Employee and Expat traits
fn additional_tax(&self) -> f64;
}
5、Trait objects
当Rust支持静态的发送的时候,它通过一个叫trait objects的方法也支持动态的发送
trait GetSound {
fn get_sound(&self) -> String;
}
struct Cat {
sound: String,
}
impl GetSound for Cat {
fn get_sound(&self) -> String {
self.sound.clone()
}
}
struct Bell {
sound: String,
}
impl GetSound for Bell {
fn get_sound(&self) -> String {
self.sound.clone()
}
}
fn make_sound(t: &T) {
println!("{}!", t.get_sound())
}
fn main() {
let kitty = Cat { sound: "Meow".to_string() };
let the_bell = Bell { sound: "Ding Dong".to_string() };
make_sound(&kitty); // Meow!
make_sound(&the_bell); // Ding Dong!
}
注:有些特定指示我并没有翻译,但也很简单,可以理解是什么意思