RUST中的trait是什么?

注:本篇文章全是由我本人通过学习所感悟的内容,所以不能保证是绝对正确的,如果有发现我文章的错误,麻烦请指出我的错误让我能明白我自己错在了哪里,希望大家一起进步。

trait

trait是什么?我先举个例子,在RUST中有非常多的数据类型,i32、u32、string、结构体和枚举等数据类型,而有的数据类型可以直接使用println!("{}", 变量);输出,我们前面了解到只有实现了display这个trait的数据类型才能被输出,如果没有则不行,你发现没这里面主要涉及到的就是数据类型,而trait本质就是为不同的数据类型实现相同的抽象功能。下面我们开始实战举例。下面是一个实例,我们定义了三个结构体及一个trait,而观察程序我们为bob和tom实现了一个attack的trait,这是两个类型,而这两个类型都有一个共同attack,这就是trait在不同的类型实现一个相同的功能,这个功能可以自定义,但是一定要满足trait中的签名,而我们直接在trait中定义的则是默认实现,就像tom中我们并没写具体的内容,而是使用的默认的trait中的内容。下面来开始正式内容把。

rust 复制代码
trait attack {
    fn can_attack(&self) {
        println!("我能攻击");
    }
}
impl attack for Bob {
    fn can_attack(&self) {
        println!("Bob能攻击");
    }
}

impl attack for Tom {
}

struct Bob {
    name: String,
    attack: bool,
}

struct Tom {
    name: String,
    attack: bool,
}

struct Xiaohong {
    name: String,
    attack: bool,
}

fn main() {
    let Bob = Bob {
        name: "Bob".to_string(),
        attack: true,
    };
    let Tom = Tom {
        name: "Tom".to_string(),
        attack: true,
    };
    let Xiaohong = Xiaohong {
        name: "Tom".to_string(),
        attack: false,
    };
    Bob.can_attack();
    Tom.can_attack();
}

//输出
Bob能攻击
我能攻击

为类型实现trait

前面说了,trait是为类型服务的,所以我们下面来拆分上面的代码演示如何为类型实现一个trait。看这个例子就可以发现,实现trait的方式其实很简单,就是impl trait的名字 for 类型的名字 {}然后在里面定义trait的方法就可以实现了,也可以在定义trait的时候直接书写一个完整的函数这样它可以默认使用。

rust 复制代码
//这里我们定义了一个结构体,也就是一个类型。
struct Bob {
    name: String,
    attack: bool,
}
//这里我们定义了一个trait并实现了can_attack方法。
trait attack {
    fn can_attack(&self) {
        println!("我能攻击");
    }
}
//这里我们为Bob类型实现了trait。
impl attack for Bob {
    fn can_attack(&self) {
        println!("Bob能攻击");
    }
}

孤儿原则

孤儿原则是什么,要为一个类型实现一个 trait,这个 trait 或这个类型必须至少有一个是在当前 crate 中定义的。为什么要这样写呢?如果两个都不在当前crate可能存在编译器并不知道你要使用那个trait或那个类型。

默认实现

以《为类型实现trait》的例子举例,当我们在trait中的函数默认定义了内容,这就是默认实现。

rust 复制代码
//这里我们定义了一个trait并实现了can_attack方法。
trait attack {
    fn can_attack(&self) {
        println!("我能攻击");
    }
}

trait约束

trait约束,什么叫trait约束呢,在函数的参数列表或返回值中,我们想定义一个参数,而我们想这个参数是实现了某个或多个trait的,这就叫trait约束。

trait作为参数

下面是一个很简单的例子,当我们想传递的参数是实现了attack的类型,我们可以直接使用impl trait名,来指定。

rust 复制代码
fn iambob(me: &impl attack) {
    println!("I am Bob!!!");
}

+号约束

+号可以在我们想指定一个参数同时实现了多种trait的情况下使用,下面我们有定义了一个fly trait,而我们想传的参数同时满足了attack和fly,我们就可以这样表示(impl trait1 + trait2),举一反三哈可以多+几个。

rust 复制代码
trait attack {
    fn can_attack(&self) {
        println!("我能攻击");
    }
}

trait fly {
    fn can_fly(&self) {
        println!("我会飞哦");
    }
}

impl fly for Bob {}

impl attack for Bob {
    fn can_attack(&self) {
        println!("Bob能攻击");
    }
}

fn iambob(me: &(impl attack + fly)) {
    println!("I am Bob!!!");
}

泛型约束

下面是另一个例子,用于泛型来约束参数,其实看一眼明白了<T: trait1 + trait2>,相反可以只是先一个或更多,自己举一反三把。

rust 复制代码
trait attack {
    fn can_attack(&self) {
        println!("我能攻击");
    }
}

trait fly {
    fn can_fly(&self) {
        println!("我会飞哦");
    }
}

impl fly for Bob {}

impl attack for Bob {
    fn can_attack(&self) {
        println!("Bob能攻击");
    }
}

fn iambob<T: attack + fly>(me: T) {
    println!("I am Bob!!!");
}

where简写

where是为了在约束很多trait的情况下让格式更美观。直接看实例吧,泛型T实现了attack+fly,语法就是在定义返回值之后的位置

where

T: trait1 + trait2,

其他泛型:其他trait,

rust 复制代码
fn iambob<T>(me: &T)
where
    T: attack + fly,
{
    println!("I am Bob!!!");
}
相关推荐
xian_wwq2 小时前
【学习笔记】Prompt Engineering 没死,只是它不再够用了-2/16
笔记·学习·prompt
210Brian3 小时前
STM32学习笔记(五)EXTI外部中断(上)
笔记·stm32·学习
xian_wwq5 小时前
【学习笔记】RAG 只是 Context Engineering 的一小块-5/16
笔记·学习·rag
iCxhust5 小时前
8088单板机VScode集成开发环境使用方法
ide·笔记·vscode·编辑器·微机原理·8088单板机
文人sec6 小时前
MySQL事务与索引做了什么?
android·笔记·mysql
NoteStream6 小时前
【C语言基础】分支和循环(上)
c语言·开发语言·c++·经验分享·笔记·算法·c#
zzm6287 小时前
位置偏差估计与无偏排序学习——WSDM 2018论文精读笔记
笔记·学习
kdxiaojie7 小时前
Linux 驱动研究 —— SDIO (1)
linux·运维·笔记·学习·sdio
Embedded-Xin8 小时前
中间件—zenoh零基础入门
linux·中间件·rust·机器人·自动驾驶·嵌入式