Rust 入门 Trait

Trait

  • Trait 翻译为 特性 特点
  • Trait 是抽象的定义共享行为
  • 与其他语言中的接口类似, 但是有些区别

定义

  • 把方法签名放在一起, 用于定义实现某种目的所必须的一组行为
  • Trait 中只有方法的签名, 没有方法的实现(在没有默认实现的情况下)
  • Trait 中可以有多个方法, 无需实现方法体
  • 实现该 Trait 的方法必须提供具体的方法实现
pub trait Summary {
    fn summarize(&self) -> String;
}

实现

  • 实现 Trait 时使用 impl Xx for Xxx{}
  • impl块中需要对 Trait 中定义的方法进行具体的实现(在没有默认实现的情况下)
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

约束

  • 可以再某个类型上实现某个 trait 的前提条件:
    • 这个类型或者这个 trait 是在本地代码中定义的
  • 无法为外部的类型实现外部的 trait:
    • 这个限制是程序属性的一部分(一致性)
    • 根据体的说就是孤儿原则
    • 此规则确保其他人的代码不能被您破坏, 反之亦然
    • 如果没有此规则, 两个 crate 可以为同一类型实现相同的 trait, Rust 编译器就不知道应该使用哪个 crate 中的实现了

默认实现

  • 有时为 trait 中的某些或全部方法提供默认的行为
  • 而不是在每个类型的每个实现中都定义自己的行为是很有用的
  • 这样当为某个特定类型实现 trait 时
  • 可以选择保留或重载每个方法的默认行为
pub trait Summary {
    fn summarize(&self) -> String{
        String::from("默认实现")
    }
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for NewsArticle {
	// 使用默认实现
}

impl Summary for Tweet {
    // 重写默认实现
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}
  • 默认实现的方法可以调用 trait 中的其他方法
pub trait Summary {
    fn summarize(&self) -> String;

    fn author(&self) -> String {
        format!("默认实现: {}", self.summarize())
    }
}

注: 无法从重写的方法内调用默认方法


Trait bounds

  • impl Trait语法
    • 此方法只能用于一些简单的情况下
pub trait Summary {
    fn summarize(&self) -> String;
}

// item 的类型为: 实现了Summary的任意类型
fn notify(item: impl Summary) {
    
}
  • 如何使用多个 Trait 约束?
    • 可以使用 + 指定多个 Trait
use std::fmt::Display;

fn notify(item: impl Summary + Display) {
    
}
  • Trait bounds语法
    • 此方法用于一些复杂的情况
    • 实际上 impl Trait 语法是此方法的一种简写
use std::fmt::Display;

fn notify<T: Summary>(item: T, old: T) {
    
}

// 指定多个 Trait
fn send<T: Summary + Display>(item: T) {
    
}
  • where 字句
    • 使用过多的 Trait bounds 也有缺点
      每个泛型有其自己的 Trait bounds
      所以有多个泛型参数的函数在名称和参数列表之间会有很长的 trait bound 信息
      这使得函数签名难以阅读
    • where 字句 编写在 方法签名后面, 用来约束泛型
// Trait bounds 语法
fn notify<T: Summary + Display, E: Clone + Debug>(a: T, b: E) {
    
}

// where 字句
fn notify2<T, E>(a: T, b: E)
    where
        T: Summary + Display,
        E: Clone + Debug,
{
    
}

使用 Trait bounds 的例子

// 此方法用于获取切片中的最大值
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut result = &list[0];
    for item in list.iter() {
        if item > result {
            result = item;
        }
    }
    result
}

fn main() {
    let arr = [1, 3, 5, 7, 9, 5, 6, 11, 10, 5, 6];
    let value = largest(&arr);
    println!("最大值为: {}", value);

    let arr = ['a', 'q', 'f', 'c', 'p', '[', 'x'];
    let value = largest(&arr);
    println!("最大值为: {}", value);

    let arr = ["关注", "收藏", "推荐"];
    let value = largest(&arr);
    println!("最大值为: {}", value);
}
如果对我分享的内容感兴趣的话  记得关注我得动态
求推荐  求收藏  求转发  求关注
posted @ 2021-06-23 15:11  Delayer  阅读(304)  评论(0编辑  收藏  举报