Rust 特质(Trait)详解
概述
特质(Trait)是 Rust 中定义共享行为的方式。类似于其他语言中的接口,但更强大。特质允许你定义抽象行为,并为不同类型提供实现。
定义特质
基本 Trait 定义
pub trait Summary {
fn summarize(&self) -> String;
}
为类型实现 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
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 条新推文: {}", tweet.summarize());
}
Trait Bound
Trait Bound 语法
pub fn notify(item: &impl Summary) {
println!("突发新闻! {}", item.summarize());
}
Trait Bound 语法(完整形式)
pub fn notify<T: Summary>(item: &T) {
println!("突发新闻! {}", item.summarize());
}
多个 Trait Bound
pub fn notify(item: &(impl Summary + Display)) {
println!("突发新闻! {}", item.summarize());
}
pub fn notify<T: Summary + Display>(item: &T) {
println!("突发新闻! {}", item.summarize());
}
where 子句
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// 函数体
}
返回实现了 Trait 的类型
返回 impl 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,
}
}
限制
// 错误:不能返回不同类型
fn returns_summarizable(switch: bool) -> impl Summary {
if switch {
NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best
hockey team in the NHL."),
}
} else {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
}
默认实现
定义默认实现
pub trait Summary {
fn summarize(&self) -> String {
String::from("(阅读更多...)")
}
}
使用默认实现
impl Summary for NewsArticle {}
fn main() {
let article = NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best
hockey team in the NHL."),
};
println!("新文章可用! {}", article.summarize());
}
调用默认实现
pub trait Summary {
fn summarize(&self) -> String {
String::from("(阅读更多...)")
}
fn summarize_author(&self) -> String {
format!("@{}", self.summarize())
}
}
Trait 作为参数
使用 impl Trait
pub fn notify(item: &impl Summary) {
println!("突发新闻! {}", item.summarize());
}
使用 Trait Bound
pub fn notify<T: Summary>(item: &T) {
println!("突发新闻! {}", item.summarize());
}
多个 Trait Bound
pub fn notify(item: &(impl Summary + Display)) {
println!("突发新闻! {}", item.summarize());
}
where 子句
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// 函数体
}
Trait Bound 与生命周期
Trait Bound 中的生命周期
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(
x: &'a str,
y: &'a str,
ann: T,
) -> &'a str
where
T: Display,
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
标准库 Trait
Display Trait
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let point = Point { x: 3, y: 4 };
println!("点: {}", point);
}
Debug Trait
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 3, y: 4 };
println!("点: {:?}", point);
}
Clone Trait
#[derive(Clone)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 3, y: 4 };
let p2 = p1.clone();
println!("p1: ({}, {}), p2: ({}, {})", p1.x, p1.y, p2.x, p2.y);
}
Copy Trait
#[derive(Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 3, y: 4 };
let p2 = p1; // p1 仍然有效
println!("p1: ({}, {}), p2: ({}, {})", p1.x, p1.y, p2.x, p2.y);
}
PartialEq 和 Eq Trait
#[derive(PartialEq, Eq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 3, y: 4 };
let p2 = Point { x: 3, y: 4 };
println!("p1 == p2: {}", p1 == p2);
}
PartialOrd 和 Ord Trait
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 3, y: 4 };
let p2 = Point { x: 5, y: 6 };
println!("p1 < p2: {}", p1 < p2);
}
Hash Trait
use std::collections::HashMap;
use std::hash::Hash;
#[derive(Hash, Eq, PartialEq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let mut map = HashMap::new();
let p = Point { x: 3, y: 4 };
map.insert(p, "原点");
println!("map: {:?}", map);
}
Trait 对象
Trait 对象的基本概念
pub trait Draw {
fn draw(&self);
}
pub struct Button {
pub width: u32,
pub height: u32,
pub label: String,
}
impl Draw for Button {
fn draw(&self) {
println!("绘制按钮: {} ({}x{})", self.label, self.width, self.height);
}
}
pub struct TextField {
pub width: u32,
pub height: u32,
pub placeholder: String,
}
impl Draw for TextField {
fn draw(&self) {
println!("绘制文本框: {} ({}x{})", self.placeholder, self.width, self.height);
}
}
使用 Trait 对象
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
impl Screen {
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
fn main() {
let screen = Screen {
components: vec![
Box::new(Button {
width: 50,
height: 10,
label: String::from("OK"),
}),
Box::new(TextField {
width: 75,
height: 10,
placeholder: String::from("输入文本"),
}),
],
};
screen.run();
}
Trait 对象的限制
// 错误:Trait 对象必须是对象安全的
pub trait Clone {
fn clone(&self) -> Self;
}
// 正确:使用泛型
pub fn clone<T: Clone>(item: &T) -> T {
item.clone()
}
关联类型
定义关联类型
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
实现关联类型
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
Counter { count: 0 }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
使用关联类型
fn main() {
let mut counter = Counter::new();
while let Some(value) = counter.next() {
println!("值: {}", value);
}
}
实际应用示例
创建一个可比较的 Trait
trait Comparable {
fn compare(&self, other: &Self) -> Ordering;
}
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Comparable for Person {
fn compare(&self, other: &Self) -> Ordering {
self.age.cmp(&other.age)
}
}
fn main() {
let p1 = Person {
name: String::from("Alice"),
age: 30,
};
let p2 = Person {
name: String::from("Bob"),
age: 25,
};
match p1.compare(&p2) {
Ordering::Less => println!("{} 比 {} 年轻", p1.name, p2.name),
Ordering::Equal => println!("{} 和 {} 同龄", p1.name, p2.name),
Ordering::Greater => println!("{} 比 {} 年长", p1.name, p2.name),
}
}
创建一个可序列化的 Trait
trait Serializable {
fn serialize(&self) -> String;
fn deserialize(s: &str) -> Result<Self, String>
where
Self: Sized;
}
struct Point {
x: i32,
y: i32,
}
impl Serializable for Point {
fn serialize(&self) -> String {
format!("{},{}", self.x, self.y)
}
fn deserialize(s: &str) -> Result<Self, String> {
let parts: Vec<&str> = s.split(',').collect();
if parts.len() != 2 {
return Err("无效的格式".to_string());
}
let x = parts[0].parse::<i32>()
.map_err(|_| "无效的 x 坐标".to_string())?;
let y = parts[1].parse::<i32>()
.map_err(|_| "无效的 y 坐标".to_string())?;
Ok(Point { x, y })
}
}
fn main() {
let p = Point { x: 3, y: 4 };
let serialized = p.serialize();
println!("序列化: {}", serialized);
let deserialized = Point::deserialize(&serialized).unwrap();
println!("反序列化: ({}, {})", deserialized.x, deserialized.y);
}
总结
本教程详细介绍了 Rust 的特质(Trait):
-
定义和实现 Trait:
- 使用
trait关键字定义 - 使用
impl为类型实现 Trait - Trait Bound 语法
- 使用
-
默认实现:
- 为 Trait 方法提供默认实现
- 可以调用默认实现
-
Trait 作为参数:
impl Trait语法- Trait Bound 语法
where子句
-
标准库 Trait:
- Display、Debug
- Clone、Copy
- PartialEq、Eq
- PartialOrd、Ord
- Hash
-
Trait 对象:
- 使用
dyn关键字 - 动态分发
- 对象安全限制
- 使用
-
关联类型:
- 在 Trait 中定义类型占位符
- 在实现中指定具体类型
Trait 是 Rust 中实现多态和代码复用的核心机制,掌握 Trait 对于编写灵活、可扩展的 Rust 代码至关重要。
下一步
在下一教程中,我们将学习 Rust 的并发编程,包括:
-
线程
-
消息传递
-
共享状态
-
Sync 和 Send Trait
-
异步编程基础
继续学习 Rust,掌握这门强大语言的更多特性!

