继续学习Rust标准库中常用的trait,在开始今天的学习之前,先把前面已经学过的trait做一个简单的复习:

  • std::str::FromStr 用于字符串slice str到其他类型的转换,一个名称为Point的类型实现了FromStr trait后,调用Point::from_str()就能完成从str到Point的转换,也可以使用str.parse()隐式调用的形式。
  • std::ops::Deref 用于不可变引用的解引用操作,Deref用于不可变引用的解引用操作,如*v。 实现Deref trait允许我们重载不可变引用的解引用运算符*。 实现了Deref trait的智能指针可以被当做常规引用来对待,以便于访问其智能指针背后的数据。Rust为了提高在函数或方法传参时的便利性,提供了Deref强制转换(Deref coercion)功能。
  • std::ops::DerefMut 用于可变引用的解引用操作,如*v = 1;。 实现DerefMut trait允许我们重载可变应用的解引用运算符*。 实现了DerefMut trait的智能指针可以被当做常规可变引用来对待。因为DerefMut tait继承了Deref trait,因此也具有"Deref强制转换功能"。
  • std::convert::From 如果一个类型实现了From<T>,则可以使用from实现从输入的T转换到该类型。实现From trait会自动为From<T>中的T实现Into trait。使用From trait还可以用于简化错误处理,在进行错误传播当上下游错误类型不一致时,通过实现From trait,使用?操作符自动实现下游到上游的错误转换。
  • 类似于From和Into,std::convert::TryFromstd::convert::TryInto 适用于易出错的转换场景,TryFrom, TryInto对比From和Into,多了个关联类型Error,try_from和try_into函数的返回值是Result,可以返回转换时出现的错误。

我们已经学习了FromStr, Deref, DerefMut, From, Into, TryFrom, TryInto这7个标准库中的trait,今天学习Default trait,使用Default trait可以为类型提供缺省值。

std::default::Default trait使用起来是十分简单的,先看一下它的定义:

1
2
3
pub trait Default {
    fn default() -> Self;
}

为类型实现Default trait有两种方式:

  • 如果类型中的包含的其他类型都实现了Default trait,就可以通过derive宏#[derive(Default)]来为类型自动实现Default trait。
  • 手动实现Default trait

例1:

1
2
3
4
5
#[derive(Default)] //无法编译通过 enum不能derive Default
pub enum PayStatus {
    Unpaid,
    Paid,
}

例2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#[derive(Debug)]
pub enum PayStatus {
    Unpaid,
    Paid,
}

// 为枚举PayStatus手工实现
impl Default for PayStatus {
    fn default() -> Self {
        PayStatus::Unpaid
    }
}

// Price的所有字段类型都实现了Default, 因此可以derive Default
#[derive(Default, Debug)]
pub struct Price {
    original_price: f64,
    discounted_price: f64,

}

// Order的所有字段类型都实现了Default,因此可以derive Default
#[derive(Default, Debug)]
pub struct Order {
    id: i64,
    pay_status: PayStatus,
    price: Price,
}

当类型实现了Default trait之后,在初始化时,可以部分初始化,其余部分使用Default::default()初始化。

例3:

1
2
3
4
5
6
7
8
9
fn main() {
   let order1 = Order::default();
   let order2 = Order {
       id: 100,
       ..Order::default()
   };
   println!("order1 = {:?}", order1);
   println!("order2 = {:?}", order2);
}

参考