【Rust 中级教程】 04 trait (2)

【Rust 中级教程】 04 trait (2)_第1张图片

0x00 开篇

今天是中秋节,是除了春节外最重大的节日,在这里我先祝大家中秋节快乐。话不多说,本篇文章继续来介绍 trait

0x01 泛型与 trait

定义泛型trait

图片

泛型它又来了,泛型和 trait 又会发生什么样的火花呢?先看下面的代码:

// 定义一个泛型trait
trait MyPrint {
    // 输出传递的参数
    fn print(&self, x: T) -> T;
}


// 测试结构体
struct Test;


// 为Test实现MyPrint
impl MyPrint for Test {


    // 返回值
    fn print(&self, x: i32) -> i32 {
        return x;
    }
}




fn main() {
    let test = Test;
    // 直接输出结果
    println!("{}", test.print(3));
}

MyPrint 是一个泛型 trait,在 trait 名称后面添加 符号则标明该 trait 是一个泛型的 trait。我们声明了一个结构体 Test,为其实现了 MyPrint 的trait。最后,我们就可以调用 print 直接输输出 i32 类型的数据了 。像类似 MyPrint 、 MyPrint 、 MyPrint等等这都不是同一类型的。

泛型约束

图片

我们还可以使用 trait 对泛型进行约束,trait 约束与泛型参数声明在一起,这种方式一般用于复杂的开发场景。示例代码如下:

    fn trait_demo(param: T)
{
    // code...
}

这里的 T 表示该参数同时实现了 TraitOne, TraitTwo, TraitOther 三个 trait。

如果存在多个泛型,我们也可以对多个泛型进行约束。示例如下:

fn multi_fun(param1: T, param2: E) {
    // code...
}

在遇到更加复杂的开发场景时,可能存在泛型存在多个 trait 约束的场景,为了避免可读性差和“头重脚轻”的问题,我们可以通过 where 关键字来进行优化。可以将约束写在函数签名后面——where + 约束条件。

multi_fun 为例,转为 where 关键字的写法如下:

fn multi_fun_where(param1: T, param2: E) where T: TraitOne, E: TraitTwo + TraitOther {
    // code...
}

由于示例代码过多,这里我就不再贴代码占用空间了,详细示例代码请点击文末 阅读原文下载。

PS:如果这里有读者读过的张汉东老版本编著的《Rust编程之道》,请不要被书中的 trait 数学的集合概念所误导,该篇内容讲述的逻辑和概念是错误的。作者回应将在第二版第4次印刷修改。附原文地址:https://github.com/ZhangHanDong/tao-of-rust-codes/issues/99

0x02 Supertraits

Rust 中没有 “继承”的概念,但是我们可以定义一个 trait 为另一个 trait 的超集。在某些文章中又叫做”子 trait“ 或者”继承“。

// Supertraits
trait Animal {
    fn speak(&self);
}


trait Dog: Animal {
    // 狗还会跳
    fn jump(&self);
}


struct SmallDog;


// 为 SmallDog 实现 Dog 的同时,也必须实现 Animal
impl Animal for SmallDog {
    fn speak(&self) {


    }
}


impl Dog for SmallDog {
    fn jump(&self) {
    }
}

我们再为 SmallDog 实现 Dog 的同时,也要为其实现 Animal。实现的顺序是无所谓的,但必须要实现,否则会产生错误。其实这点类似于 Java 中的接口继承。

0x03 trait 中的 Self

在 trait 中,我们可以使用关键字 Self 作为类型。这里的 Self 是首字母大写的。我们先看下官方代码示例。下面内容可以仅作为了解。

【Rust 中级教程】 04 trait (2)_第2张图片

这是官方源码中的 Clone trait,clone 方法返回了 Selfclone 方法的返回类型就是自身类型, 这也就意味着 Self 其实就是自身类型。我们再进一步剖析它。我这里随便点了几个实现,下面源码来自 client.rs

【Rust 中级教程】 04 trait (2)_第3张图片

我们从这两个 impl 代码块中,可以清晰的看出,其实 Self 其实就是当前类型的别名。第一个 impl 块中,Self 是 Group 的别名,在第二个 impl 块中,Self 是 Literal 的别名。

0x04 小结

本篇文章着重介绍了泛型与 trait 结合使用的场景。这也是应对复杂场景的一种解决办法,也是我们必须要掌握的重点。有关 trait 的相关知识还有很多,下一篇文章依然还是 trait。

你可能感兴趣的:(Rust,中级教程,rust,开发语言,后端)