参考: https://rustmagazine.github.io/rust_magazine_2021/chapter_7/rusts-standard-library-traits.html
0x01 trait 的默认方法
trait 和java 的interface 理解起来比较接近。
struct SomeType07;
struct OtherType07;
impl Trait07 for SomeType07 {}
impl Trait07 for OtherType07 {
fn method(&self) {
info!("other type 07 method");
}
}
fn main() {
tracing_subscriber::fmt().init();
SomeType07.method();
OtherType07.method();
}
0x02 给系统类型添加方法
可以为 i32、String 这类系统类型添加自定义的方法,便于使用
trait Trait08 {
fn is_even(&self) -> bool;
}
impl Trait08 for u32 {
fn is_even(&self) -> bool {
self % 2 == 0
}
}
fn main() {
tracing_subscriber::fmt().init();
let a = 19_u32;
info!("{} is even: {}", a, a.is_even());
}
0x03 关于继承
结论就是不要使用继承,因为它不是覆盖
心智负担太重 -_-!
trait Trait09 {
fn say_hello(&self) {
info!("trait 09 say_hello");
}
}
trait Trait10: Trait09 {}
0x04 trait 对象
trait 用于编译阶段,而trait 对象主要提供运行时多态能力。
trait 对象是一个指针,它没有大小。使用关键字dyn
fn example(condition: bool, vec: Vec<i32>) -> Box<dyn Iterator<Item = i32>> {
let iter = vec.into_iter();
if condition {
Box::new(iter.map(|x| x * 2))
} else {
Box::new(iter.filter(|&n| n >= 2))
}
}
常见用法:
trait Trait {}
&dyn Trait
Box<dyn Trait>
Rc<dyn Trait>
Arc<dyn Trait>
0x05 标记 trait
不包含方法体的空trait ,用于“标记”某个属性
trait BlankTrait{}
0x06 Send ,Sync
线程安全的数据标识。
0x07 Sized
类型大小在编译期可知
0x08 Clone/Copy
会产生复制动作,性能占用较大
0x09 Any
动态参数化的实现手段,通过 match type_id 进行匹配
trait Any: 'static {
fn type_id(&self) -> TypeId;
}
fn map_any(mut any: Box<dyn Any>) -> Box<dyn Any> {
if let Some(num) = any.downcast_mut::<i32>() {
*num += 1;
} else if let Some(string) = any.downcast_mut::<String>() {
*string += "!";
} else if let Some(point) = any.downcast_mut::<Point>() {
point.inc();
}
any
}
0x10 格式化 trait
Trait Placeholder Description
--------------------------------------------------
Display {} 显示表示
Debug {:?} 调试表示
Octal {:o} 八进制表示
LowerHex {:x} 小写十六进制表示
UpperHex {:X} 大写十六进制表示
Pointer {:p} 内存地址
Binary {:b} 二进制表示
LowerExp {:e} 小写指数表示
UpperExp {:E} 大写指数表示
0x11 转化为 String 的方式: Display & ToString
trait ToString {
fn to_string(&self) -> String;
}
0x12 运算符重载
可以对
struct增加运行符逻辑
Trait(s) 分类(Category) 操作符(Operator(s)) 描述(Description)
Add 算术 + 相加
AddAssign 算术 += 相加并赋值
BitAnd 算术 & 按位与
BitAndAssign 算术 &= 按位与并赋值
BitXor 算术 ^ 按位异或
BitXorAssign 算术 ^= 按位异或并赋值
Div 算术 / 除
DivAssign 算术 /= 除并赋值
Mul 算术 * 乘
MulAssign 算术 *= 乘并赋值
Neg 算术 - 一元求反
Not 算术 ! 一元逻辑求反
Rem 算术 % 求余
RemAssign 算术 %= 求余并赋值
Shl 算术 << 左移
ShlAssign 算术 <<= 左移并赋值
Shr 算术 >> 右移
ShrAssign 算术 >>= 右移并赋值
Sub 算术 - 减
SubAssign 算术 -= 减并赋值
使用例:
#[derive(Clone, Copy)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, rhs: Point) -> Point {
Point {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 3, y: 4 };
let p3 = p1 + p2;
assert_eq!(p3.x, p1.x + p2.x); // ✅
assert_eq!(p3.y, p1.y + p2.y); // ✅
}
0x13 闭包 trait
Trait(s) 分类(Category) 操作符(Operator(s)) 描述(Description)
Fn 闭包 (...args) 不可变闭包调用
FnMut 闭包 (...args) 可变闭包调用
FnOnce 闭包 (...args) 一次性闭包调用
0x14 其他 trait
仅作用于
&变量
image.png
#![allow(unused)]
fn main() {
use std::ops::Deref;
struct Human {
health_points: u32,
}
enum Weapon {
Spear,
Axe,
Sword,
}
// a Soldier is just a Human with a Weapon
struct Soldier {
human: Human,
weapon: Weapon,
}
impl Deref for Soldier {
type Target = Human;
fn deref(&self) -> &Human {
&self.human
}
}
enum Mount {
Horse,
Donkey,
Cow,
}
// a Knight is just a Soldier with a Mount
struct Knight {
soldier: Soldier,
mount: Mount,
}
impl Deref for Knight {
type Target = Soldier;
fn deref(&self) -> &Soldier {
&self.soldier
}
}
enum Spell {
MagicMissile,
FireBolt,
ThornWhip,
}
// a Mage is just a Human who can cast Spells
struct Mage {
human: Human,
spells: Vec<Spell>,
}
impl Deref for Mage {
type Target = Human;
fn deref(&self) -> &Human {
&self.human
}
}
enum Staff {
Wooden,
Metallic,
Plastic,
}
// a Wizard is just a Mage with a Staff
struct Wizard {
mage: Mage,
staff: Staff,
}
impl Deref for Wizard {
type Target = Mage;
fn deref(&self) -> &Mage {
&self.mage
}
}
fn borrows_human(human: &Human) {}
fn borrows_soldier(soldier: &Soldier) {}
fn borrows_knight(knight: &Knight) {}
fn borrows_mage(mage: &Mage) {}
fn borrows_wizard(wizard: &Wizard) {}
fn example(human: Human, soldier: Soldier, knight: Knight, mage: Mage, wizard: Wizard) {
// all types can be used as Humans
borrows_human(&human);
borrows_human(&soldier);
borrows_human(&knight);
borrows_human(&mage);
borrows_human(&wizard);
// Knights can be used as Soldiers
borrows_soldier(&soldier);
borrows_soldier(&knight);
// Wizards can be used as Mages
borrows_mage(&mage);
borrows_mage(&wizard);
// Knights & Wizards passed as themselves
borrows_knight(&knight);
borrows_wizard(&wizard);
}
0x14 转换 trait ( From & Into)
不同类型之间相间转换
#![allow(unused)]
fn main() {
struct Point {
x: i32,
y: i32,
}
impl From<(i32, i32)> for Point {
fn from((x, y): (i32, i32)) -> Self {
Point { x, y }
}
}
impl From<[i32; 2]> for Point {
fn from([x, y]: [i32; 2]) -> Self {
Point { x, y }
}
}
fn example() {
// 使用 From
let origin = Point::from((0, 0));
let origin = Point::from([0, 0]);
// 使用 Into
let origin: Point = (0, 0).into();
let origin: Point = [0, 0].into();
}
0x15 Error Handling
生产开发中,已经转换为 anyhow, thiserror 处理异常了。
0x16 AsRef & AsMut
在函数内部获取参数的所有权
fn take_as_ref_str<T: AsRef<str>>(s: T) {
let p: &str = s.as_ref();
info!("take_as_ref_str {}", p);
}
fn main() {
tracing_subscriber::fmt().init();
let val = "中国".to_string();
take_as_ref_str(val);
}
