19、Traits(“接口”)

Traits

重新看之前的Ticket结构体

pub struct Ticket {
    title: String,
    description: String,
    status: String,
}

之前我们所有的assertions(测试)都使用的是Ticket的字段。

assert_eq!(ticket.title(), "A new title");

如果我们想要直接比较两个Ticket实例呢?

let ticket1 = Ticket::new(/* ... */);
let ticket2 = Ticket::new(/* ... */);
ticket1 == ticket2

 

编译器会阻止我们:

error[E0369]: binary operation `==` cannot be applied to type `Ticket`
  --> src/main.rs:18:13
   |
18 |     ticket1 == ticket2
   |     ------- ^^ ------- Ticket
   |     |
   |     Ticket
   |
note: an implementation of `PartialEq` might be missing for `Ticket`

Ticket是一个新类型,它没有什么附加的行为。

Rust 不会因为两个 Ticket 实例包含字符串,就神奇地推断出如何比较它们。

不过,Rust 编译器正在朝着正确的方向引导我们:它提示我们可能缺少 PartialEq 的实现。

PartialEq是一个trait

 

什么是traits

traits是Rust定义interfaces(接口)的方式。

traits定义了一组方法,类型必须实现这些方法,才算符合trait的规范。

定义一个trait

定义trait的语法是这样的:

trait <TraitName>{
	fn <method_name>(<parameters>)-><return_type>;
}

 

比如,我们可以定义一个名为MaybeZerotrait,该trait要求它的实现者定义一个is_zero方法:

trait MaybeZero {
    fn is_zero(self) -> bool;
}

实现一个trait

我们使用impl关键字去实现一个trait,和处理常规的方法有些类似,但是有些不同,以下是实现trait的语法:

impl <TraitName> for <TypeName> {
    fn <method_name>(<parameters>) -> <return_type> {
        // Method body
    }
}

 

比如给自定义数字类型WarppingU32实现MaybeZerotrait:

pub struct WrappingU32 {
    inner: u32,
}

impl MaybeZero for WrappingU32 {
    fn is_zero(self) -> bool {
        self.inner == 0
    }
}

调用trait方法

使用.操作符即可调用trait方法,就像我们调用常规方法那样:

let x = WrappingU32 { inner: 5 };
assert!(!x.is_zero());

 

要想成功调用trait方法,必须确保两件事情:

  • 类型必须实现trait
  • trait必须在作用域内

为了满足后者,我们可以使用use crate::MaybeZero把想要使用的trait导入进来,以成功调用trait方法。

 

以下两种情况,不需要使用use把trait导入进来:

  • trait的调用者与trait本身在同一个模块里
  • trait定义在标准库的prelude(引子,序幕)中,prelude是可以自动导入到所有Rust程序里面的一组traittypes的集合。就好比是在每一个Rust模块的开头都添加了std::prelude::*

练习

既然学了trait的定义和调用,那么练习肯定就是这个了,这次的练习让我们实现一个trait,trait里面有一个方法

// Define a trait named `IsEven` that has a method `is_even` that returns a `true` if `self` is
// even, otherwise `false`.
//
// Then implement the trait for `u32` and `i32`.

也挺简单的,我一开始的代码是这样:

trait IsEven{
    fn is_even(&self) -> bool;
}
impl IsEven for u32{
    fn is_even(&self) -> bool{
        if self%2==0{
            true
        }
        else{
            false
        }
    }
}
impl IsEven for i32{
    fn is_even(&self) -> bool{
        if self%2==0{
            true
        }
        else{
            false
        }
    }
}

结果check的时候,怎么也不行,报错提示,找不到is_even这个方法。

我寻思应该是要加上pub吧,试了给方法加,不行(

 

后来发现原来是要给trait的定义块加pub

pub trait IsEven{
    fn is_even(&self) -> bool;
}

www,哈基C,难道你连这个都debug不出来吗(

 

好了,这一节的学习就先到这里了

阅读剩余
THE END