📕
innohub
  • KEEP LEARNING
  • WebInfo
    • JS 部分运算符操作
    • javascript 中的object array
    • 错误处理以及异常捕获
    • JavaScript Bases
    • LaoZi & Confucius
  • PyInfo
    • Python3 输入与输出
    • Python3OS
    • python 修饰器的使用
    • python3 与mysql数据库连接使用实例
    • Format-specifier
    • CGI初学踩坑
    • Django 项目测试
    • Assert-info
    • 使用ngnix和uWSGI配置Django
    • write|SVN​
    • Matplotlib 基本使用
    • 重读 Python 官方文档
    • Python3 Base
    • python3 多线程
    • Python3 函数解析
    • python3 str 对象的基本操作
    • protocl buffers
    • Iterator-Generator
    • Django base
    • Decorator 2
    • Export to wheel or egg-info
    • 三. 运算、数据及逻辑
  • GoInfo
    • Info
      • Select 语句使用
      • First class function
      • Work Pools
      • StructTag
      • Go struct
      • 常用函数
      • Strings操作
      • Golang Bases
      • 数组以及切片
      • 文件操作
      • Golang 中的指针类型
      • Golang Map 类型
      • Reflection
      • 函数闭包
      • 接口
      • Panic and Recover
      • Go中的错误处理
      • 并发
      • defer usage
      • Method in golang
      • Object-oriented Programming
      • Goalng 包管理机制
  • RustInfo
    • Info
      • 包、crate、模块
      • Rust 中的错误处理
      • 智能指针
      • 泛型 generics
      • 数据布局与内存对齐
      • Functions and methods
      • 无畏并发
      • Actix-web 基本使用
      • Got from guessing game
      • 结构体的使用
      • Rust 中的函数式语言功能
      • 集合类型
      • 枚举以及模式匹配
      • Slice 类型
      • 生命周期
      • 测试
      • Rust 中的所有权
      • trait
      • 不安全 Rust
      • Format_print
      • Rust 通用编程概念
      • Macro
  • OS
    • info
      • 内存屏障 -- Part 1
      • 内存屏障 -- Part 2
      • CPU 上下文切换
      • 文件读写与零拷贝
      • ELF 文件
  • MySql
    • info
      • MySql 架构与历史
      • 02-key
  • kubernetes
    • 第二章 k8s 基本概念
    • 第一章 Kubernetes -- 伟大舵手
  • Redis
    • info
      • Redis 总览
      • 02-underline-ds
  • Shell&CInfo
    • GCC 与make的使用
    • C++ 中 malloc 与 new
    • 位运算符操作
    • Base of C macro
    • C 语言中 extern 关键字的用法
  • Distributed
    • info
      • 分布式理论概述
  • Java
    • info
      • Java 内存模型
  • Prometheus
    • Prometheus -- 不灭之火
Powered by GitBook
On this page
  • 1. 泛型的作用
  • 2. 结构体中定义的泛型
  • 3. 枚举中定义泛型
  • 4. 方法中定义泛型
  • 5. 泛型代码的性能

Was this helpful?

  1. RustInfo
  2. Info

泛型 generics

[TOC]

1. 泛型的作用

每一个语言都有一个高效处理重复概念的工具,在 Rust 中使用的是Generics。泛型是具体类型或者其他属性的抽象代替,可以定义泛型,规定一类具有相似行为的类型。为了编写一份可以用于多种具体值的代码,可以使用泛型作为参数或者返回值。一些枚举类型上,Option<T>, Result<T, E>,Vec<T>,HashMap<K, V> 都使用了泛型。

可以使用泛型显著减少代码的重复。一般而言,可以使用一个函数处理代码的重复。比如求一个数组最大值的函数。但是有一个问题是,对于不同类型而言,需要编写不同的函数,这显然也是一种重复。此时,泛型就派上用场了。

fn largest_i32(list: &[i32]) -> i32 {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn largest_char(list: &[char]) -> char {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

这两个函数有着相同的代码,所以让我们在一个单独的函数中引入泛型参数来消除重复。

为了参数化函数签名中的类型,需要给每一个类型参数起一个名字,任何标识符都可以作为类型参数名。一般类型使用T表示,错误使用E表示。当一个函数使用一个泛型参数时,需要在函数名后定义该泛型。

fn largest<T>(list: &[T]) -> T;

但是注意,泛型并不是说所有类型都可以使用。一个泛型指定的范围越大,那么可以使用的公共方法越少。对于泛型的约束通常使用 trait 来进行。 trait以类似接口的形式,定义了一些行为规范,每一个实现了某个trait的类型都必须实现所有方法。

use std::cmp::PartialOrd;
pub fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    // The type which impls PartialOrd and Copy trait can use
    // the function
    let mut largest = list[0];    // Copy trait
    for &item in list.iter() {
        if item > largest {      // PartialOrd trait
            largest = item;
        }
    }

    largest
}

上述代码中的赋值操作,需要实现了Copy trait 的类型才可以进行访问, 因为list 是一个引用类型,不可以进行move。否则默认实现 move 操作。 比较操作需要实现了std::cmp::PartialOrdtrait的类型才可以调用。

2. 结构体中定义的泛型

可以使用<>语法定义具有泛型参数类型字段的结构体,如果所需要的泛型字段类型相同,可以使用同一个泛型,如果不一样必须使用更多的泛型,不同的泛型可以使用同一个类型。

#[derive(Debug)]
pub struct Point<T, U> {
    pub x: T,
    pub y: U,
}


struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let wont_work = Point { x: 5, y: 4.0 };
}

error[E0308]: mismatched types
 --> src/main.rs:7:38
  |
7 |     let wont_work = Point { x: 5, y: 4.0 };
  |                                      ^^^ expected integral variable, found
floating-point variable
  |
  = note: expected type `{integer}`
             found type `{float}`

3. 枚举中定义泛型

枚举类型的字段可以定义泛型,用以包含不同类型的数据。一个典型用例就是Option<T>.Result<T, E>.

4. 方法中定义泛型

可以为定义中包含泛型的结构体或者枚举类型的定义方法,但是需要在impl关键字后添加相应的泛型参数,在类型后面也需要添加泛型参数。

// Methods for Point
impl<T, U> Point<T, U> {
    pub fn x(&self) -> &T {
        &self.x
    }
    pub fn y(&self) -> &U {
        &self.y
    }
}

除了可以为所有泛型定义相同的方法,也可以为泛型赋予特定类型,然后实现相应的方法。此时不需要impl后的<>

// Methods for the specific type
impl Point<f64, f64> {
    pub fn distance_from_origin(&self) -> f64 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

5. 泛型代码的性能

Rust实现的泛型,使得使用泛型的代码与使用具体类型的代码具有相同的性能。通过在编译时进行泛型代码的单态化(monomorphization)来保证效率。单态化通过填充编译时所使用的具体类型,从而使得每一个泛型在编译时都有唯一的具体类型的与之绑定。这样就实现了编写通用代码,同时得到特定代码性能的目的。

以Option<T>为例,进行单态化时,一个对应i32,那么单态化时,可以表示为Option_i32从而实现了类型的具体化。

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}
Previous智能指针Next数据布局与内存对齐

Last updated 5 years ago

Was this helpful?