Rust 泛型与特性
泛型函数与结构体、trait 定义与实现、trait bound、以及动态分发。
Key Points泛型是编译期单态化(零成本),`dyn Trait` 是运行期虚表(有开销)。
泛型函数
Rust
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut max = list[0];
for &item in list.iter() {
if item > max {
max = item;
}
}
max
}
fn main() {
println!("{}", largest(&[1, 5, 3]));
println!("{}", largest(&[1.5, 0.2, 3.7]));
println!("{}", largest(&['a', 'z', 'm']));
}Output
5
3.7
zT: PartialOrd + Copy is a trait bound: T must be comparable and copyable. Without it item > max fails to compile — a generic function may only use declared capabilities.
泛型结构体
Rust
#[derive(Debug)]
struct Pair<T> {
first: T,
second: T,
}
impl<T: std::fmt::Display> Pair<T> {
fn show(&self) {
println!("({}, {})", self.first, self.second);
}
}
// 只对特定类型实现
impl Pair<f64> {
fn average(&self) -> f64 {
(self.first + self.second) / 2.0
}
}
fn main() {
let p = Pair { first: 1, second: 2 };
p.show();
let f = Pair { first: 1.0, second: 2.0 };
f.show();
println!("{}", f.average());
}Output
(1, 2)
(1, 2)
1.5trait
Rust
trait Summary {
// 必须实现
fn summarize(&self) -> String;
// 默认实现
fn preview(&self) -> String {
format!("{}...", &self.summarize()[..10.min(self.summarize().len())])
}
}
struct Article {
title: String,
body: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, self.body)
}
}
struct Tweet {
user: String,
text: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.user, self.text)
}
fn preview(&self) -> String {
self.text.clone()
}
}
fn main() {
let a = Article { title: "Rust".into(), body: "所有权很重要".into() };
let t = Tweet { user: "tom".into(), text: "今天学了 trait".into() };
println!("{}", a.summarize());
println!("{}", t.summarize());
}Output
Rust: 所有权很重要
@tom: 今天学了 trait静态分发 vs 动态分发
Rust
fn static_dispatch<T: Summary>(item: &T) {
println!("{}", item.summarize());
}
fn dynamic_dispatch(item: &dyn Summary) {
println!("{}", item.summarize());
}
fn main() {
let a = Article { title: "x".into(), body: "y".into() };
static_dispatch(&a);
dynamic_dispatch(&a);
// dyn 才能放进同质容器
let items: Vec<Box<dyn Summary>> = vec![
Box::new(Article { title: "a".into(), body: "b".into() }),
Box::new(Tweet { user: "u".into(), text: "t".into() }),
];
for i in &items {
println!("{}", i.summarize());
}
}Output
x: y
x: y
a: b
@u: t| Form | Dispatch | Cost | Use |
|---|---|---|---|
<T: Trait> | 静态,单态化 | 零 | 性能敏感、类型固定 |
impl Trait | 静态 | 零 | 参数或返回值 |
&dyn Trait | 动态,虚表 | 一次间接调用 | 混合类型集合 |
Generics are monomorphised:
largest::<i32> and largest::<f64> compile to two separate bodies. Heavy generics bloat the binary and slow builds; dyn has one body at the cost of a vtable jump.常见标准库 trait
| Trait | Method | Meaning |
|---|---|---|
Display | fmt | {} 打印 |
Debug | fmt | {:?} 打印 |
Clone | clone | 显式复制 |
Default | default | 零值构造 |
From / Into | from / into | 类型转换 |
Iterator | next | 迭代 |
Deref | deref | 解引用与自动转换 |
泛型函数
Rust
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut max = list[0];
for &item in list.iter() {
if item > max {
max = item;
}
}
max
}
fn main() {
println!("{}", largest(&[1, 5, 3]));
println!("{}", largest(&[1.5, 0.2, 3.7]));
println!("{}", largest(&['a', 'z', 'm']));
}Output
5
3.7
zT: PartialOrd + Copy 是 trait bound:告诉编译器「T 必须能比较、能复制」。没有 bound 时 item > max 编译不过——泛型函数只能用它声明过的能力。
泛型结构体
Rust
#[derive(Debug)]
struct Pair<T> {
first: T,
second: T,
}
impl<T: std::fmt::Display> Pair<T> {
fn show(&self) {
println!("({}, {})", self.first, self.second);
}
}
// 只对特定类型实现
impl Pair<f64> {
fn average(&self) -> f64 {
(self.first + self.second) / 2.0
}
}
fn main() {
let p = Pair { first: 1, second: 2 };
p.show();
let f = Pair { first: 1.0, second: 2.0 };
f.show();
println!("{}", f.average());
}Output
(1, 2)
(1, 2)
1.5trait
Rust
trait Summary {
// 必须实现
fn summarize(&self) -> String;
// 默认实现
fn preview(&self) -> String {
format!("{}...", &self.summarize()[..10.min(self.summarize().len())])
}
}
struct Article {
title: String,
body: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, self.body)
}
}
struct Tweet {
user: String,
text: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.user, self.text)
}
fn preview(&self) -> String {
self.text.clone()
}
}
fn main() {
let a = Article { title: "Rust".into(), body: "所有权很重要".into() };
let t = Tweet { user: "tom".into(), text: "今天学了 trait".into() };
println!("{}", a.summarize());
println!("{}", t.summarize());
}Output
Rust: 所有权很重要
@tom: 今天学了 trait静态分发 vs 动态分发
Rust
fn static_dispatch<T: Summary>(item: &T) {
println!("{}", item.summarize());
}
fn dynamic_dispatch(item: &dyn Summary) {
println!("{}", item.summarize());
}
fn main() {
let a = Article { title: "x".into(), body: "y".into() };
static_dispatch(&a);
dynamic_dispatch(&a);
// dyn 才能放进同质容器
let items: Vec<Box<dyn Summary>> = vec![
Box::new(Article { title: "a".into(), body: "b".into() }),
Box::new(Tweet { user: "u".into(), text: "t".into() }),
];
for i in &items {
println!("{}", i.summarize());
}
}Output
x: y
x: y
a: b
@u: t| 写法 | 分发 | 开销 | 适用 |
|---|---|---|---|
<T: Trait> | 静态,单态化 | 零 | 性能敏感、类型固定 |
impl Trait | 静态 | 零 | 参数或返回值 |
&dyn Trait | 动态,虚表 | 一次间接调用 | 混合类型集合 |
泛型会单态化:
largest::<i32> 和 largest::<f64> 编译成两份独立的机器码。所以泛型用太多会让二进制变大、编译变慢。dyn 只有一份代码,代价是虚表跳转。常见标准库 trait
| Trait | 方法 | 含义 |
|---|---|---|
Display | fmt | {} 打印 |
Debug | fmt | {:?} 打印 |
Clone | clone | 显式复制 |
Default | default | 零值构造 |
From / Into | from / into | 类型转换 |
Iterator | next | 迭代 |
Deref | deref | 解引用与自动转换 |