一、特征
特征(trait)相当于 Java 中的接口
// 定义特征
trait Instrument {
// 演奏方法
fn play(&self) -> String;
// 调音方法:默认方法
fn tune(&self) -> String {
String::from("Tuning to standard pitch...")
}
// 关联类型,表示声音的类型
type Sound;
fn sound(&self) -> Self::Sound;
}
// 吉他
struct Guitar {
// 弦数
strings: u32,
}
impl Instrument for Guitar {
fn play(&self) -> String {
format!("Strumming {} strings with a rhythm!", self.strings)
}
type Sound = String; // 吉他的声音用字符串描述
fn sound(&self) -> Self::Sound {
"Twang!".to_string()
}
}
// 钢琴
struct Piano {
// 键数
keys: u32,
}
impl Instrument for Piano {
fn play(&self) -> String {
format!("Pressing {} keys in a melody!", self.keys)
}
fn tune(&self) -> String {
format!("Adjusting {} keys with a tuning hammer!", self.keys)
}
type Sound = u32; // 钢琴的声音用响度(分贝)表示
fn sound(&self) -> Self::Sound {
85 // 假设钢琴声为85分贝
}
}
fn main() {
let guitar = Guitar {strings:6};
let piano = Piano {keys:88};
println!("{}", guitar.play());
println!("{}", guitar.tune());
println!("{}", guitar.sound());
println!("{}", piano.play());
println!("{}", piano.tune());
println!("{}", piano.sound());
}
二、泛型
基础语法
假设我们要写一个函数,找出数组中的最大值。如果只针对i32类型,代码可能是这样的:
fn max_i32(list: &[i32]) -> i32 {
let mut max = list[0];
for &item in list {
if item > max {
max = item;
}
}
max
}
现在,如果想支持 f64 类型呢?可以再写一个几乎一模一样的 max_f64 函数,但这显然很浪费。泛型提供了一个优雅的解决方案:
fn max<T>(list: &[T]) -> T {
let mut max = list[0];
for &item in list {
if item > max { // 注意:这里编译器不知道 T 能不能比较大小( > 运算符),需要类型约束,后面会解决
max = item;
}
}
max
}
特征限界
// PartialOrd 确保T可以比较大小;Copy 允许 list[0] 被复制到 max,避免所有权问题
fn max<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut max = list[0];
for &item in list {
if item > max {
max = item;
}
}
max
}
// 如果约束比较多,也可以使用如下语法
fn max2<T>(list: &[T]) -> T
where
T: PartialOrd + Copy,
{
let mut max = list[0];
for &item in list {
if item > max {
max = item;
}
}
max
}
fn main() {
let ints = [1, 5, 3];
let floats = [1.2, 0.5, 2.8];
println!("Max int: {}", max(&ints)); // 输出: Max int: 5
println!("Max float: {}", max(&floats)); // 输出: Max float: 2.8
}
注意:如上的代码,编译器会为 i32 和 f64 分别生成两个具体函数,类似于手写的 max_i32 和 max_f64 函数。这意味着泛型没有运行时开销,性能与直接编写具体类型一致。
结构体/枚举/方法泛型
// 结构体:表示二维坐标
struct Coord<T> {
x: T,
y: T,
}
// 带多种类型的结构体
struct Pair<T, U> {
first: T,
second: U,
}
// 枚举:表示成功或失败的结果
enum Result<T> {
Ok(T),
Err(String),
}
// 方法:为Coord实现获取x坐标的功能
impl<T> Coord<T> {
fn get_x(&self) -> &T {
&self.x
}
}
fn main() {
let int_coord = Coord { x: 3, y: 4 };
let float_coord = Coord { x: 1.5, y: 2.5 };
let pair = Pair {
first: 42,
second: "hello",
};
let result = Result::Ok(100);
println!("x: {}", int_coord.get_x()); // 输出: x: 3
}