个人专栏:

 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客

Java基础:Java基础_IT闫的博客-CSDN博客

c语言:c语言_IT闫的博客-CSDN博客

MySQL:数据结构_IT闫的博客-CSDN博客

数据结构:​​​​​​数据结构_IT闫的博客-CSDN博客

C++:C++_IT闫的博客-CSDN博客

諒C51单片机:C51单片机(STC89C516)_IT闫的博客-CSDN博客

基于HTML5的网页设计及应用:基于HTML5的网页设计及应用_IT闫的博客-CSDN博客​​​​​​

累python:python_IT闫的博客-CSDN博客

离散数学:离散数学_IT闫的博客-CSDN博客

​​​​​​諒Linux:​​​​Linux_Y小夜的博客-CSDN博客

Rust:Rust_Y小夜的博客-CSDN博客

欢迎收看,希望对大家有用!

目录

Trait简介

定义一个Trait

在类型上实现trait

 实现trait的约束

默认实现

trait作为参数

Trait Bound语法

通过+指定多个trait bound

通过where简化trait bound

实现Trait作为返回类型

使用Trait Bound有条件的实现方法

Trait简介

        trait 定义了某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共同行为。可以使用 trait bounds 指定泛型是任何拥有特定行为的类型。

        注意:trait 类似于其他语言中的常被称为 接口(interfaces)的功能,虽然有一些不同。

        Trait :抽象的定义共享行为。        Trait bounds(约束):泛型类型参数指定为实现特定行为的参数。        Trait与其他语言的接口(interface)类似,但有些区别。

定义一个Trait

        一个类型的行为由其可供调用的方法构成。如果可以对不同类型调用相同的方法的话,这些类型就可以共享相同的行为了。trait 定义是一种将方法签名组合起来的方法,目的是定义一个实现某些目的所必需的行为的集合。

        展示了一个表现这个概念的公有 Summary trait 的定义:

pub trait Summary {

fn summarize(&self) -> String;

}

        在方法签名后跟分号,而不是在大括号中提供其实现。接着每一个实现这个 trait 的类型都需要提供其自定义行为的方法体,编译器也会确保任何实现 Summary trait 的类型都拥有与这个签名的定义完全一致的 summarize 方法。

        trait 体中可以有多个方法:一行一个方法签名且都以分号结尾。

        只有只有方法签名,没有具体实现。

        实现该trait的类型必须提供具体的方法实现。

在类型上实现trait

pub struct NewsArticle {

pub headline: String,

pub location: String,

pub author: String,

pub content: String,

}

impl Summary for NewsArticle {

fn summarize(&self) -> String {

format!("{}, by {} ({})", self.headline, self.author, self.location)

}

}

pub struct Tweet {

pub username: String,

pub content: String,

pub reply: bool,

pub retweet: bool,

}

impl Summary for Tweet {

fn summarize(&self) -> String {

format!("{}: {}", self.username, self.content)

}

}

        在类型上实现 trait 类似于实现与 trait 无关的方法。区别在于 impl 关键字之后,我们提供需要实现 trait 的名称,接着是 for 和需要实现 trait 的类型的名称。在 impl 块中,使用 trait 定义中的方法签名,不过不再后跟分号,而是需要在大括号中编写函数体来为特定类型实现 trait 方法所拥有的行为。

 实现trait的约束

      现在库在 NewsArticle 和 Tweet 上实现了Summary trait,crate 的用户可以像调用常规方法一样调用 NewsArticle 和 Tweet 实例的 trait 方法了。唯一的区别是 trait 必须和类型一起引入作用域以便使用额外的 trait 方法。这是一个二进制 crate 如何利用 aggregator 库 crate 的例子:

use aggregator::{Summary, Tweet};

fn main() {

let tweet = Tweet {

username: String::from("horse_ebooks"),

content: String::from(

"of course, as you probably already know, people",

),

reply: false,

retweet: false,

};

println!("1 new tweet: {}", tweet.summarize());

}

        不能为外部类型实现外部 trait。例如,不能在 aggregator crate 中为 Vec 实现 Display trait。这是因为 Display 和 Vec 都定义于标准库中,它们并不位于 aggregator crate 本地作用域中。这个限制是被称为 相干性(coherence)的程序属性的一部分,或者更具体的说是 孤儿规则(orphan rule),其得名于不存在父类型。这条规则确保了其他人编写的代码不会破坏你代码,反之亦然。没有这条规则的话,两个 crate 可以分别对相同类型实现相同的 trait,而 Rust 将无从得知应该使用哪一个实现。        

默认实现

        有时为 trait 中的某些或全部方法提供默认的行为,而不是在每个类型的每个实现中都定义自己的行为是很有用的。这样当为某个特定类型实现 trait 时,可以选择保留或重载每个方法的默认行为。

pub trait Summary {

fn summarize(&self) -> String {

String::from("(Read more...)")

}

}

        如果想要对 NewsArticle 实例使用这个默认实现,可以通过 impl Summary for NewsArticle {} 指定一个空的 impl 块。

默认实现允许调用相同 trait 中的其他方法,哪怕这些方法没有默认实现。

pub trait Summary {

fn summarize_author(&self) -> String;

fn summarize(&self) -> String {

format!("(Read more from {}...)", self.summarize_author())

}

}

为了使用这个版本的 Summary,只需在实现 trait 时定义 summarize_author 即可:

impl Summary for Tweet {

fn summarize_author(&self) -> String {

format!("@{}", self.username)

}

}

注意无法从相同方法的重载实现中调用默认方法。

trait作为参数

pub fn notify(item: &impl Summary) {

println!("Breaking news! {}", item.summarize());

}

        对于 item 参数,我们指定了 impl 关键字和 trait 名称,而不是具体的类型。该参数支持任何实现了指定 trait 的类型。适用于简单的情况。

Trait Bound语法

  impl Trait 语法适用于直观的例子,它实际上是一种较长形式我们称为 trait bound语法的语法糖。它看起来像:

pub fn notify(item: &T) {

println!("Breaking news! {}", item.summarize());

}

        这与之前的例子相同,不过稍微冗长了一些。trait bound 与泛型参数声明在一起,位于尖括号中的冒号后面。

  impl Trait 很方便,适用于短小的例子。更长的 trait bound 则适用于更复杂的场景。

pub fn notify(item1: &impl Summary, item2: &impl Summary) {

        这适用于 item1 和 item2 允许是不同类型的情况(只要它们都实现了 Summary)。不过如果你希望强制它们都是相同类型呢?这只有在使用 trait bound 时才有可能:

pub fn notify(item1: &T, item2: &T) {

通过+指定多个trait bound

        如果 notify 需要显示 item 的格式化形式,同时也要使用 summarize 方法,那么 item 就需要同时实现两个不同的 trait:Display 和 Summary。

pub fn notify(item: &(impl Summary + Display)) {

+ 语法也适用于泛型的 trait bound:

pub fn notify(item: &T) {

通过where简化trait bound

        使用过多的 trait bound 也有缺点。每个泛型有其自己的 trait bound,所以有多个泛型参数的函数在名称和参数列表之间会有很长的 trait bound 信息,这使得函数签名难以阅读。为此,Rust 有另一个在函数签名之后的 where 从句中指定 trait bound 的语法。所以除了这么写:

fn some_function(t: &T, u: &U) -> i32 {

还可以像这样使用 where 从句:

fn some_function(t: &T, u: &U) -> i32

where

T: Display + Clone,

U: Clone + Debug,

{

实现Trait作为返回类型

fn returns_summarizable() -> impl Summary {

Tweet {

username: String::from("horse_ebooks"),

content: String::from(

"of course, as you probably already know, people",

),

reply: false,

retweet: false,

}

}

        返回一个只是指定了需要实现的 trait 的类型的能力在闭包和迭代器场景十分的有用不过。

        这只适用于返回单一类型的情况。

使用Trait Bound有条件的实现方法

        通过使用带有 trait bound 的泛型参数的 impl 块,可以有条件地只为那些实现了特定 trait 的类型实现方法。

use std::fmt::Display;

struct Pair {

x: T,

y: T,

}

impl Pair {

fn new(x: T, y: T) -> Self {

Self { x, y }

}

}

impl Pair {

fn cmp_display(&self) {

if self.x >= self.y {

println!("The largest member is x = {}", self.x);

} else {

println!("The largest member is y = {}", self.y);

}

}

}

        也可以对任何实现了特定 trait 的类型有条件地实现 trait。对任何满足特定 trait bound 的类型实现 trait 被称为 blanket implementations,它们被广泛的用于 Rust 标准库中。

好文阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: