目录

泛型与 Trait

泛型(Generics)

泛型允许编写适用于多种类型的代码,避免重复。

泛型函数

fn largest<T>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest { // 这里需要 PartialOrd 约束
            largest = item;
        }
    }
    largest
}
 
fn main() {
    let numbers = vec![34, 50, 25, 100, 65];
    println!("最大: {}", largest(&numbers));
 
    let chars = vec!['y', 'm', 'a', 'q'];
    println!("最大: {}", largest(&chars));
}

注意:以上代码需要加 PartialOrd 约束才能编译,我们稍后介绍。

泛型结构体

struct Point<T> {
    x: T,
    y: T,
}
 
fn main() {
    let integer = Point { x: 5, y: 10 };       // Point<i32>
    let float = Point { x: 1.0, y: 4.0 };      // Point<f64>
}

泛型结构体多个类型参数

struct Point<T, U> {
    x: T,
    y: U,
}
 
fn main() {
    let both = Point { x: 5, y: 4.0 }; // Point<i32, f64>
}

泛型枚举

enum Option<T> {
    Some(T),
    None,
}
 
enum Result<T, E> {
    Ok(T),
    Err(E),
}

泛型方法

struct Point<T> {
    x: T,
    y: T,
}
 
impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}
 
// 专门为 f64 类型实现的方法
impl Point<f64> {
    fn distance_from_origin(&self) -> f64 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}
 
fn main() {
    let p = Point { x: 5, y: 10 };
    println!("p.x = {}", p.x());
 
    let f = Point { x: 3.0, y: 4.0 };
    println!("距离原点: {}", f.distance_from_origin());
}

Trait

Trait 定义共享行为,类似于其他语言的接口(interface)。

定义和实现 Trait

trait Summary {
    fn summarize(&self) -> String;
}
 
struct Article {
    title: String,
    author: String,
    content: String,
}
 
impl Summary for Article {
    fn summarize(&self) -> String {
        format!("《{}》- {}", self.title, self.author)
    }
}
 
struct Tweet {
    username: String,
    content: String,
}
 
impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("@{}: {}", self.username, self.content)
    }
}
 
fn main() {
    let article = Article {
        title: String::from("Rust 入门"),
        author: String::from("小明"),
        content: String::from("内容..."),
    };
    println!("{}", article.summarize());
 
    let tweet = Tweet {
        username: String::from("rust_fan"),
        content: String::from("学习 Rust 中!"),
    };
    println!("{}", tweet.summarize());
}

默认实现

Trait 可以提供默认方法实现:

trait Summary {
    fn summarize(&self) -> String {
        String::from("(阅读更多...)")
    }
}
 
impl Summary for Article {} // 使用默认实现
 
impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("@{}: {}", self.username, self.content)
    }
}

Trait 作为参数

// 方式一:impl Trait 语法
fn notify(item: impl Summary) {
    println!("通知: {}", item.summarize());
}
 
// 方式二:Trait Bound 语法
fn notify<T: Summary>(item: T) {
    println!("通知: {}", item.summarize());
}
 
// 多个参数
fn notify2(item1: impl Summary, item2: impl Summary) {}
fn notify2<T: Summary>(item1: T, item2: T) {}

多重约束

use std::fmt::Display;
 
// 同时要求 impl Summary + Display
fn notify(item: impl Summary + Display) {}
 
// 或使用 where 子句
fn some<T, U>(t: T, u: U)
where
    T: Display + Clone,
    U: Clone + Summary,
{}

返回 Trait

fn returns_summarizable() -> impl Summary {
    Article {
        title: String::from("Rust 泛型和 Trait"),
        author: String::from("老师"),
        content: String::from("内容..."),
    }
}

常用标准库 Trait

Trait 用途
Clone 提供 clone() 方法进行深拷贝
Copy 标记类型使用按位复制(栈上类型)
Debug 提供 {:?} 格式化
Display 提供 {} 格式化
PartialEq 提供 ==, != 比较
PartialOrd 提供 <, >, , >= 比较
Hash 提供哈希计算
Iterator 实现迭代器

本章实践

use std::fmt::Display;
 
trait Greet {
    fn greet(&self) -> String;
}
 
struct Person {
    name: String,
    age: u8,
}
 
impl Greet for Person {
    fn greet(&self) -> String {
        format!("你好,我叫{},今年{}岁", self.name, self.age)
    }
}
 
fn print_greet(item: impl Greet + Display) {
    println!("{}", item.greet());
}
 
fn main() {
    let p = Person {
        name: "小明".into(),
        age: 25,
    };
    print_greet(p);
}

本章小结