当前位置: 首页 > news >正文

Rust泛型详解

泛型可以看作构建函数和类型定义的模板。标准库中有很多常见类型例如Result<T, E>Option<T>Vec<T>等都是泛型实现的。主要用于代码的特化。Rust是静态类型语言,因此泛型的类型参数(T)需要在编译期解析为具体类型,这种特性就是参数化多态性。泛型的实现还采用单态化技术,会根据实际传入的类型参数,将泛型实例化为唯一的专用类型。
泛型的优点:

  • 代码复用:只需编写一套代码,可以用于不同的类型。
  • 重构:重构变得更简单,因为泛型只有一份源码,不需要维护多份类型不同但功能相同的代码
  • 扩展性:可扩展性强,未来即使出现新的数据类型,泛型代码依然适用。
  • 更不容易犯错:使用泛型减少了大量重复代码的实现,潜在的错误也变少。
  • 独特功能:Rust中的泛型机制带来了独特的能力->函数重载

泛型函数

泛型函数是使用类型参数的函数模板,用于创建具体函数,

  • 类型参数要在函数名后使用<>声明
  • 命名惯例使用大驼峰命名,第一个类型参数一般用T,接着是U、V等
fn function_name<T>(param: T)->T {let variable: T;
}

示例

fn swap<T, U>(tuple: (T, U))->(U, T) {(tuple.1, tuple.0)
}
fn main() {let tuple = (1, "hello");let tuple1 = ("hello".to_string(), "world".to_string());let tuple2 = (3.14, 98);let t_swap = swap(tuple);let t1_swap = swap(tuple1);let t2_swap = swap(tuple2);println!("{:?}", t_swap);println!("{:?}", t1_swap);println!("{:?}", t2_swap);}

编译器自动推导出了具体的类型,编译器会根据函数定义,选择调用对应的函数版本。

编译器通常能从参数类型推导出对应的类型参数,但如果无法推导出具体类型,就需要显式指定类型

function_name::<type,...>(arg,...)

示例

fn do_something<T: Default>()->T {let value: T = T::default();value
}fn main() {let ret = do_something::<i8>();println!("{}", ret);
}

泛型约束

在编译期,编译器对这些参数类型的实际类型并不了解,因此,编译器需要对使用类型参数的代码添加合理的限制。
可以把类型参数看作一个装着某种工具的黑盒子,你不知道里面具体是什么,但是你想安全地执行一些操作,这个时候会看有关于盒子内容的提示会非常有用。
trait约束就是用来限制类型参数的行为,可以限定单个或多个trait,每个trait都会告诉编译器类型参数应该具备哪些能力。

使用(:)用于添加trait约束,如<T: Trait>

use std::fmt::Display;fn do_something<T: Display>(t: T) {println!("{}",t);
}fn main() {do_something(20);
}

因为格式化字符串中的{}占位符需要实现Display trait,编译器不能假设类型参数T具有此特性。

可以给类型参数指定多个限制

<T: Trait1+Trait2+...>

示例

use std::{cmp::Ordering, fmt::Display};fn largest<T: Ord+Display>(arg1: T, arg2: T) {match arg1.cmp(&arg2) {Ordering::Less => println!("{arg1} < {arg2}"),Ordering::Greater => println!("{arg1} > {arg2}"),Ordering::Equal => println!("{arg1} == {arg2}"),}
}fn test() {largest(1, 2);largest("arg1", "arg2");largest('a', 'b');largest(100, 99);}
fn main() {test();
}

largest是一个泛型函数,用于比较并输出结果。
要支持比较,这个类型必须实现Ord trait; 使用占位符{},要求这个类型必须实现Display,这两个trait都被应用与T的约束。

where

where是约束的另一种表示方法,这种方法的表达力更强

use std::fmt::Debug;fn do_something<T>(t: T)
where T: Debug {println!("{:?}", t);
}
fn main() {let tuple = (1,2,3,5);do_something(tuple);
}

泛型结构体

除了函数之外,结构体同样支持泛型,在定义结构体时,可以在结构体名称后面加上<T> 之后该参数可以被用于结构体定义的任何位置(字段和方法)

struct Wrapper<T> {internal: T
}
fn main() {let obj = Wrapper {internal: 24};/* 会被单态化成i32类型struct wrapper {internal: i32}*/}

由于单态化机制,编译器会用i32类型实例化Wrapper结构体

泛型结构体不仅可以使用类型参数定义字段,还可以将类型参数用于方法定义。

use std::fmt::Debug;#[derive(Debug)]
struct Wrapper<T> {internal: T
}impl<T: Copy> Wrapper<T> {fn get(&self) -> T {self.internal}
}fn main() {let obj = Wrapper { internal: 20 };let obj1 = Wrapper {internal: "hello".to_string() };let ret = obj.get();println!("{}",ret);
}

只有字段类型实现了Copy的T,才能调用该impl块内的所有方法。由于set方法需要创建T类型的拷贝,所以需要T实现Copy trait。而String类型不属于实现了Copy trait的类型,因此实例化后不具备get方法。

除了从结构体那里继承的类型参数,方法也可以定义专属于自己的类型参数。

use std::fmt::{Debug, Display};#[derive(Debug)]
struct Wrapper<T> {internal: T
}impl<T: Copy+Display> Wrapper<T> {fn display<U: Display>(&self, prefix: U, suffix: U) {println!("{prefix} {} {suffix}", self.internal);}
}fn main() {let obj = Wrapper { internal: 20 };obj.display("(",")");
}

关联函数

你可以将泛型与关联函数一起使用

use std::fmt::{Debug, Display};#[derive(Debug)]
struct Wrapper<T> {internal: T
}
impl<T: Display> Wrapper<T> {fn hello(name: T) {println!("hello {}",name)}
}fn main() {Wrapper::hello("张三");
}

由于hello方法传入了一个&str类型的参数,编译器可以推断出T的类型,因此就不需要手动指定。
而下面这种情况需要手动指定类型:

use std::fmt::{Debug, Display};#[derive(Debug)]
struct Wrapper<T> {internal: T
}
impl<T> Wrapper<T> {fn hello() {println!("helloworld");}
}fn main() {Wrapper::<&str>::hello();
}
http://www.dtcms.com/a/423945.html

相关文章:

  • 官方手表网站网站专题分类
  • 新乡网站建设方案搜狗网址大全下载安装
  • 关于可视化卷积核和特征图的深度理解
  • 【mysql】Mybatisplus BINARY {0} LIKE CONCAT(‘%‘, {1}, ‘%‘)写这句话是什么意思
  • 开发避坑指南(59):Vue3中高效删除数组元素的方法
  • wordpress建站要用模板吗wordpress搜索筛选
  • 安卓 WPS Office v18.21.0 国际版
  • 衡阳网站推广优化公司行业网站开发运营方案
  • 临海房产中介网站如何制作网站平台管理
  • 做网站多少人建e室内设计网官网平面图
  • git mere 错误后的回滚处理
  • Java开发入门(一)--- JDK与环境变量配置
  • 最好的营销型网站建设公司报电子商务(网站建设与运营)
  • 从0到1制作一个go语言游戏服务器(二)web服务搭建
  • 网站使用流程图昆明网站建设天锐科技
  • (uniapp)基于vue3父子组件间传递参数与方法
  • 铁岭开原网站建设高中课程免费教学网站
  • 高校网站群建设方案网站建设目录结构设计
  • 静态网站源码野花韩国视频在线观看免费高清
  • Windows下NVM保姆级指南:安装、切换版本、指定路径+淘宝镜像配置,一次搞定!
  • 杭州营销型网站建设杭州租车网站建设
  • 网站开发基础知识网站开发怎么连接sqlserver
  • 基于AC6366C做AI语音鼠标
  • 刘诗雯现身TCL品牌活动,雷鸟34Q9显示器同台竞技
  • 东莞百域网站建设公司手机网站开发屏幕尺寸一般是多少
  • 理财经理如何提高职场技能实现晋升
  • 【碎片化学习】SpringBoot中的自动配置(Auto Configuration)
  • PC16550 FIFO接收方式研究
  • 做基金的网站哪个好用什么程序做资讯类网站
  • 图书馆网站建设申请国外做仿牌网站