Rust 中的 Trait 是什么

Rust 中的Trait 定义了特定类型所具有的功能,并且可以与其他类型共享。它指定了可以在类型上调用的方法。

例如,假设我们有不同类型的文本数据:

  • 一个NewsArticle用于新闻报道的结构
  • 和一个Tweet用于推文的结构。
两者都可以共享一个典型行为:总结内容。
我们使用Trait 来定义这种共享行为。

pub trait Summary {
    fn summarize(&self) -> String;
}

Summary 特征Trait有一个summarize方法。任何实现此特征的类型都必须提供此方法的自身版本。

实现Trait 
要实现Trait 特征,您需要为您的类型定义特征指定的方法。以下是我们对 NewsArticle 和 Tweet 的操作方法。

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)
    }
}

现在,NewsArticle 和 Tweet 都可以使用 summary 方法。这允许我们在这些类型的实例上调用 summary。

默认实现
Trait 特征也可以有默认方法实现。如果我们不想为每种类型编写相同的方法,我们可以提供一个默认值:

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

如果类型需要特定的行为,仍然可以覆盖此默认值。

使用Trait 作为参数
Trait 特征可用于定义函数参数。如果我们希望函数接受任何实现 Summary 的类型,我们可以这样写:

pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

返回实现Trait 的类型
我们还可以指定一个函数返回一个实现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,
    }
}

这使我们能够返回符合 Summary 特征的不同类型,而无需暴露具体类型。

条件实现
有时,您希望仅当满足某些条件时方法才可用。Rust 允许条件实现:

impl<T: Display + PartialOrd> Pair<T> {
    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);
        }
    }
}

这里,仅当 T 同时实现了 Display 和 PartialOrd 时,cmp_display 才可用。

结论
Trait 特征是 Rust 中的一项强大功能,可帮助定义和共享跨类型行为。它们使您的代码更加模块化、可重用且更易于理解。通过将错误移至编译时,它们可确保您的代码稳健且高效。祝您编码愉快!