第七章 Rust 特征(trait)与泛型

一、特征

特征(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
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容