Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Rust中的泛型

Rust中的泛型

作者头像
端碗吹水
发布于 2022-06-01 01:09:03
发布于 2022-06-01 01:09:03
98200
代码可运行
举报
运行总次数:0
代码可运行

[TOC]

泛型程序设计是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。泛型编程的中心思想是从携带类型信息的具体的算法中抽象出来,得到一种可以与不同的数据类型表示相结合的算法,从而生成各种有用的软件。泛型编程是一种软件工程中的解耦方法,很多时候,我们的算法并不依赖某种特定的具体类型,通过这种方法,我们就可以将“类型”从算法和数据结构的具体示例中抽象出来。


泛型作为函数参数的类型

考虑以下问题:编写一个函数,这个函数接收两个数字,然后返回较大的那个数字。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn largest(a: u32, b: u32) -> u32 {
    if a > b {
        a
    } else {
        b
    }
}

这个函数能工作,但它只能比较两个 u32 类型数字的大小。现在除了想比较两个 u32 外,还想比较两个 f32。有一种可以行的办法,我们可以定义多个 largest 函数,让它们分别叫做 largest_u32largest_f32… 这能正常工作,但不太美观。我们可以使用泛型语法对上述代码进行修改:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn largest<T: std::cmp::PartialOrd>(a: T, b: T) -> T {
    if a > b {
        a
    } else {
        b
    }
}

fn main() {
    println!("{}", largest::<u32>(1, 2));
    println!("{}", largest::<f32>(1.0, 2.1));
}

其中,std::cmp::PartialOrd 被称作泛型绑定,在之后的课程中我们会对此进行解释。


结构体中的泛型

我们还可以使用泛型语法定义结构体,结构体中的字段可以使用泛型类型参数。下面的代码展示了使用 Point&lt;T&gt; 结构来保存任何类型的 x 和 y 坐标值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}

上述代码创建了一个 x 和 y 都是同一类型的 Point 结构体,但同时一个结构体中也可以包含多个不同的泛型参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct Point<T, U> {
    x: T,
    y: T,
    z: U,
}

fn main() {
    let integer = Point { x: 5, y: 10, z: 15.0 };
    let float = Point { x: 1.0, y: 4.0, z: 8 };
}

但是要注意,虽然一个结构体中可以包含任意多的泛型参数,但我仍然建议拆分结构体以使得一个结构体中只使用一个泛型参数。过多的泛型参数会使得阅读代码的人难以阅读。


结构体泛型的实现

我们可以在带泛型的结构体上实现方法,它的语法与普通结构体方法相差不大,只是要注意在它们的定义中加上泛型类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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());
}

我们也可以在某种具体类型上实现某种方法,例如下面的方法将只在 Point&lt;f32&gt; 有效。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
impl Point<f32> {
    fn distance_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

使用traits定义共同的行为

某一类数据可能含有一些共同的行为:例如它们能被显示在屏幕上,或者能相互之间比较大小。我们将这种共同的行为称作 Traits。我们使用标准库 std::fmt::Display 这个 traits 举例,这个 traits 实现了在 Formatter 中使用空白格式 {} 的功能。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pub trait Display {
    pub fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use std::fmt;

struct Point {
    x: i32,
    y: i32,
}

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

let origin = Point { x: 0, y: 0 };

assert_eq!(format!("The origin is: {}", origin), "The origin is: (0, 0)");

使用 Traits 作为参数类型

在知道如何定义和实现 Traits 后,我们就可以探索如何使用 Traits 来定义接受许多不同类型的函数。这一切都与 Java 中的接口概念类似,也就是所谓的鸭子类型。事实上它们的使用场景也基本上是类似的。

我们定义一个 display 函数,它接收一个实现了 Display Traits 的参数 item。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pub fn display(item: &impl std::fmt::Display) {
    println!("My display item is {}", item);
}

item 的参数类型是 impl std::fmt::Display 而不是某个具体的类型(例如 Point),这样,任何实现了 Display Traits 的数据类型都可以作为参数传入该函数。


自动派生

Rust 编译器可以自动为我们的结构体实现一些 Traits,这种自动化技术被称作派生。例如,在编写代码的过程中最常见的一个需求就是将结构体输出的屏幕上,除了使用上节课提到的手工实现的 Display,也可以采用自动派生技术让 Rust 编译器自动帮你添加代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 1, y: 2 };
    println!("{:?}", p);
}

Debug Trait 允许将数据结构使用 {:?} 格式进行格式化。

自动派生有一个前提是,该结构体中全部字段都实现了指定的 Trait,例如,上面例子中的 i32 和 i64 就已经实现了 Debug Trait。

现在,我们来为 Point 实现另一个 Trait:PartialEq。该特征允许两个数据使用 == 进行比较。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 1, y: 2 };
    println!("{}", p1 == p2);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
做COX生存分析是否需要把连续值变成高低二分组?
在进行Cox回归分析时,是否需要将连续变量转化为分类变量(如高低二分组)取决于研究目的和数据特性。Cox回归模型可以处理连续变量,但有时将连续变量转化为分类变量可以提供更明确的临床意义和更易解释的结果。
生信技能树
2025/01/07
2020
做COX生存分析是否需要把连续值变成高低二分组?
你只能哭着说明明没有相关性
因为是转录组测序,所以基因表达量可以很容易根据物种对应的gtf文件进行蛋白编码基因和非编码基因的表达量拆分,前面的代码略过哈,我们直接看拆分好的两个表达量矩阵:
生信技能树jimmy
2021/05/18
4210
你只能哭着说明明没有相关性
基于CellMiner数据库的基因表达与药敏分析
CellMiner数据库,主要是通过国家癌症研究所癌症研究中心(NCI)所列出的60种癌细胞为基础而建立的。该数据库最初发表于2009年,后于2012年在Cancer Research杂志上进行了更新,题目为“CellMiner: a web-based suite of genomic and pharmacologic tools to explore transcript and drug patterns in the NCI-60 cell line set”。大家后期在使用该数据库记得应用相关文献。
DoubleHelix
2022/11/24
4.5K0
基于CellMiner数据库的基因表达与药敏分析
回答公众号留言的2个关于相关性分析的问题
https://www.bilibili.com/video/BV1Ne41147eR
用户7010445
2020/07/28
9290
如果你觉得相关性热图不好看,或者太简陋
就有粉丝提问,把单细胞亚群使用 AverageExpression 函数做成为了亚群矩阵,是不是忽略了单细胞亚群的异质性呢?毕竟每个单细胞亚群背后都是成百上千个具体的细胞啊。代码如下所示:
生信技能树jimmy
2022/01/10
6740
如果你觉得相关性热图不好看,或者太简陋
m6A图文复现06-样本相关性检验与Peak Calling
前面我们分享了 跟着Nature Medicine学MeDIP-seq数据分析,数据和代码都是公开,这个2G的压缩包文件,足以学习3个月,写60篇教程。同时也分享了 全套MeRIP-seq文章图表复现代码,其实MeRIP-seq其实就是RNA水平的,又叫做m6a测序。
生信技能树
2021/08/25
3K0
m6A图文复现06-样本相关性检验与Peak Calling
相关性热图、圈图、弦图(笔记)
如下所示,可以看到有多个样品,每个样品都有多个基因表达量,这个时候我们比较关心的是这些基因的表达量相关性(在多个样品),基因与基因之间有两两组合相关性:
生信技能树
2023/02/27
2.6K0
相关性热图、圈图、弦图(笔记)
多分组差异分析解决方案(1)循环T检验
主要方法:将其中某一组设置为实验组,其余几组统一设置为对照组。 第一步读取数据,合并表达矩阵和分组文件 #=========================================================================== #=========================================================================== rm(list = ls(all.names = TRUE)) options(st
用户1359560
2021/06/10
1.2K0
多分组差异分析解决方案(1)循环T检验
R计算mRNA和lncRNA之间的相关性+散点图
我们在做表达谱数据分析的时候,经常需要检测基因两两之间表达的相关性。特别是在构建ceRNA网络的时候,我们需要去检查构成一对ceRNA的mRNA和lncRNA之间的表达是否呈正相关。前面给大家分享过R计算多个向量两两之间相关性,今天小编就给大家分享一个实际的应用案例,用R去批量的检测大量mRNA跟lncRNA之间表达的相关性,并绘制散点图。
生信交流平台
2022/09/21
8540
R计算mRNA和lncRNA之间的相关性+散点图
比较不同流程(limma/voom,edgeR,DESeq2 )差异分析的区别
距离第一次听说生信已经十几年了,现在是邋遢大叔重新开始学代码,精力确实已不像从前,各位入坑还是要乘早。后来约莫在5年前,课题组当时有个RNA-Seq数据,lab meeting时听瑞典小哥在汇报DEGs筛选,当时感觉好是神奇。其实陆陆续续也有过学习的念头,但在对自己的各种纵容下,想法又逐渐隐没。直到2月前,机缘巧合参加了生信技能树培训,才进一步强化了自己学习生信技术的信念。
生信技能树
2021/01/05
5.2K0
转录组差异分析—基本流程
读取RawCounts.csv文件,其文件形式如下图行名为ensembleid,列名为样本名称。
sheldor没耳朵
2024/07/29
2340
转录组差异分析—基本流程
一网打尽转录组差异分析!!!
差异分析在转录组数据分析中占据着举足轻重的地位,是揭示基因表达变化的关键步骤。然而,面对众多如DESeq2、limma和edgeR等转录组分析R包,分析人员常常面临选择困境。本文旨在深入探讨这些常用差异分析R包的特点、优劣,以及它们与t检验/Wilcox秩和检验(Wilcox-rank-sum test)在差异分析结果上的异同点。
生信学习者
2024/06/11
4550
一网打尽转录组差异分析!!!
肿瘤免疫细胞浸润与临床相关性分析
Profiles of immune infiltration in colorectal cancer and theirclinical significant: A gene expression- based study
DoubleHelix
2020/04/07
6.9K0
TCGA癌症数据挖掘之预后模型建立和评价
表达矩阵只需要tumor数据,不要normal,将其去掉,新表达矩阵数据命名为exprSet;
生信技能树
2022/06/08
5.9K1
TCGA癌症数据挖掘之预后模型建立和评价
WGCNA仅仅是划分基因模块,其它都是附加分析
曾老师给我分享了一篇数据挖掘的文章,里面的WGCNA非常奇怪,我之前没见过这样的模块与表型的相关性热图
生信技能树
2023/09/04
1.3K0
WGCNA仅仅是划分基因模块,其它都是附加分析
在Python中创建相关系数矩阵的6种方法
相关系数矩阵(Correlation matrix)是数据分析的基本工具。它们让我们了解不同的变量是如何相互关联的。在Python中,有很多个方法可以计算相关系数矩阵,今天我们来对这些方法进行一个总结
deephub
2023/09/24
1.1K0
在Python中创建相关系数矩阵的6种方法
R中循环处理多组间相关性分析
R语言数据分析指南
2023/11/30
2620
R中循环处理多组间相关性分析
生物信息数据分析教程视频——11-筛选相关性基因
视频地址:http://mpvideo.qpic.cn/0bc3tiabgaaaneakrfjtfvrvbgwdconaaeya.f10002.mp4? 参考: 如何合理的展示相关性分析结果??
DoubleHelix
2022/12/15
7680
生物信息数据分析教程视频——11-筛选相关性基因
重复一篇Cell文献的PCA图
这天,接到了生信技能树创始人jimmy老师的一个任务,要重复一篇CELL文章中的一个图示:
生信技能树
2019/05/08
2.1K0
重复一篇Cell文献的PCA图
【画图】如何批量展现基因表达相关性?
现在已经有明确的实验证明,跟SARS病毒一样,新冠状病毒2019-nCoV与宿主细胞的ACE2受体结合[1]。上次教程已经给大家演示了,GTEx数据库有人各组织中基因表达谱数据,下载整理这个数据可以绘制出ACE2受体在人体组织中的表达量情况以及可能的功能有哪些。
Chris生命科学小站
2023/02/28
4680
【画图】如何批量展现基因表达相关性?
推荐阅读
相关推荐
做COX生存分析是否需要把连续值变成高低二分组?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验