11.泛型、trait和生命周期(上)

标题

一、泛型数据的引入

下面是两个函数,分别用来取得整型和符号型vector中的最大值

rust 复制代码
use std::fs::File;

fn get_max_float_value_from_vector(src: &[f64]) -> f64{

    let mut max = src[0];

    for &item in src.iter(){
        if item > max {
            max = item;
        }
    }

    max
}

fn get_max_int_value_from_vector(src: &[i32]) -> i32{
    let mut max = src[0];

    for &item in src.iter(){
        if item > max {
            max = item;
        }
    }

    max
}
fn main() {
    let x = vec![12, 21, 78, 56, 77];
    let y = vec![11.5, 100.3, 1.0, 90.1];

    println!("max x: {}", get_max_int_value_from_vector(&x));   //max x: 78
    println!("max y: {}", get_max_float_value_from_vector(&y)); //max y: 100.3
}
  • 只看函数内容,两个函数完成相同
  • 不同的地方在于函数名、返回值和参数
  • 返回值和参数又具有很大的关联性;
  • 这就造成了函数冗余

二、改写为泛型函数

函数get_max_int_value_from_vectorget_max_float_value_from_vector完全可以改写成一个泛型函数,如

rust 复制代码
fn get_max_value_from_vector<T>(src: &[T]) -> T{}

则代码变成

rust 复制代码
fn get_max_value_from_vector<T>(src: &[T]) -> T{
    let mut max = src[0];

    for &item in src.iter(){
        if item > max {
            max = item;
        }
    }

    max
}
fn main() {
    let x = vec![12, 21, 78, 56, 77];
    let y = vec![11.5, 100.3, 1.0, 90.1];

    println!("max x: {}", get_max_value_from_vector(&x));   //max x: 78
    println!("max y: {}", get_max_value_from_vector(&y)); //max y: 100.3
}

编译报错

  • 解决方法在5.7 使用trait bounds修复get_max_value_from_vector的错误中进行。

三、结构体/枚举中的泛型定义

  • 下面将坐标值的x,y都改成泛型
rust 复制代码
struct Point<T>{
    x: T,
    y: T,
}

enum Option<T> {
    Some(T),
    None,
}

//两个泛型
enum Result<T, E> {
    Ok(T),
    Err(E),
}

四、方法定义中的泛型

rust 复制代码
struct Point<T>{
    x: T,
    y: T,
}

impl<T> Point<T>{
    fn x(&self) -> &T{
        &self.x
    }
}
fn main() {
    let p = Point{x:5, y:10};
    println!("p.x = {}", p.x());   //p.x = 5
}
  • 在impl后面声明 T,这样就可以在Point<T>上实现的方法中使用;
  • 在impl后声明泛型T ,Rust 就知道Point的尖括号中的类型是泛型而不是具体类型;

下面展示了一个没有在impl 之后(没有尖括号)声明泛型的例子,这里使用了一个具体类型

rust 复制代码
impl Point<f32> {
    fn distance_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}
  • 代码计算点实例与坐标 (0.0, 0.0) 之间的距离;
  • 这段代码意味着Point<f32> 类型会有一个方法distance_from_origin,
  • 其他不是 f32 类型的Point<T> 实例则没有定义此方法;

结构体定义中的泛型类型参数并不总是与结构体方法签名中使用的泛型是同一类型。

下例的结构体Point<T, U> 上定义了一个方法mixup。这个方法获取另一个 Point 作为参数,而它可能与调用 mixup 的 self 是不同的 Point 类型。这个方法用 self 的 Point 类型的 x 值(类型 T)和参数的 Point 类型的 y 值(类型 W)来创建一个新 Point 类型的实例

rust 复制代码
struct Point<T, U> {
    x: T,
    y: U,
}

impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}

fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c'};

    let p3 = p1.mixup(p2);

    println!("p3.x = {}, p3.y = {}", p3.x, p3.y); // p3.x = 5, p3.y = c
}
  • p1是一个有 i32 类型的 x(其值为 5)和 f64 的 y(其值为 10.4)的 Point;
  • p2则是一个有着字符串 slice 类型的 x(其值为 "Hello")和 char 类型的 y(其值为 c)的 Point;
  • 在p1上以 p2 作为参数调用 mixup 会返回一个 p3,它会有一个 i32 类型的 x;
  • x 来自 p1,并拥有一个 char 类型的 y,y 来自 p2;
相关推荐
敲代码的瓦龙2 分钟前
Android?基础UI控件!!!
java·开发语言
Hesionberger4 分钟前
LeetCode 78:子集生成全攻略
java·开发语言·数据结构·python·算法·leetcode·职场和发展
bzmK1DTbd4 分钟前
Swagger API文档:Java RESTful服务的自动生成
java·开发语言·restful
kyriewen19 分钟前
你等的Babel编译,够喝三杯咖啡了——用Rust重写的SWC,只需眨个眼
前端·javascript·rust
身如柳絮随风扬22 分钟前
Java对象在计算机中的执行原理:从JVM内存模型到对象创建全过程
java·开发语言·jvm
河西石头24 分钟前
听AI的血的教训!PPOCRLabel部署与PyQt5的安装避坑-百分百成功!
开发语言·人工智能·python·pyqt5安装·ppocrlabel的部署
野生技术架构师29 分钟前
我总结了这份2026最新版Java面试题库(背完这一套就够了)
java·开发语言·面试
AIGC设计所29 分钟前
网络安全8大就业领域和待遇对比!
运维·开发语言·网络·安全·web安全·php
xxjj998a33 分钟前
PHP与汇编:从Web到硬件的编程差异
开发语言·汇编·php
装杯让你飞起来啊1 小时前
Kotlin 条件判断 if / when 与智能转换 smart cast
开发语言·python·kotlin