Rust 泛型
Rust 泛型
泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。在Rust中编译时编译器会将泛型代码具化为不同具体类型的多份代码,所以泛型代码只是提供了一种通用代码的抽象,并不能减少编译后真正生成的代码量。
泛型创建
泛型函数
fn give_me<T>(value:T){
let _=value;
}
泛型函数的创建需要在方法名和圆括号间放置泛型参数,之后就可以将该泛型参数视为类型使用。
使用
fn main() {
let a="generics";
let b=1024;
give_me(a);
give_me(b);
}
泛型类型
泛型类型的创建需要在类型名和{}间放置泛型参数,之后就可以将该泛型参数视为类型使用。
结构体:
struct GenericStruct<T>(T);
struct Container<T>{
item:T,
}
使用:
let i=GenericStruct(1);
let s=GenericStruct(String::from("1111"));
let ic=Container{item:1};
let is=Container{item:String::from("is")};
枚举:
enum Transmission <T>{
Singal(T),
NoSingal,
}
使用:
let ei=Transmission::Singal(1);
let es=Transmission::Singal(String::from("222"));
let eni=Transmission::<i32>::NoSingal;
let ens:Transmission<String>=Transmission::NoSingal;
注意:使用泛型ZST枚举实例要使用::<>(turbofish)来指明泛型参数是哪种类型。
泛型实现:
泛型实现要在impl后声明泛型参数,然后就可以把泛型参数当作具体类型使用。
拿上一部分的Container为例,为其实现方法:
impl<T> Container<T> {
fn new(item:T)->Self{
Container{item}
}
}
使用:
let container_i32=Container::new(1);
let container_str=Container::new(String::from("111"));
还可以为具体类型参数提供实现:
impl Container<i32>{
// fn new(item:i32)->Self{
// Container{item}
// }
fn toString(&self)->String{
self.item.to_string()
}
}
这种具体类型参数的实现只对此类型可用,并且不能和泛型实现函数名冲突。
特征区间(trait bounds)
上述所有示例程序,我们都只是简单的提供了一个占位符来表示类型,编译器并不知道具体的类型信息,所以我们除了用它们来表示类型外,并不能对这些占位符或者它们表示的变量调用方法,好在Rust提供了trait bounds来告知编译器相关的类型信息来完成这项工作。
我们可以在泛型声明处使用“:”来对类型占位符进行一些约束来告知编译器相关的类型信息。一些例子如下:
在方法上使用trait bounds:
trait Person{
fn sleep(){
println!("person need sleep");
}
fn get_name(&self)->&str;
}
struct Student{name:String}
impl Person for Student {
fn get_name(&self)->&str{
&self.name
}
}
fn who<T:Person>(anyone:&T){
println!("I'm {}",anyone.get_name());
}
fn doing_at_night<T:Person>(anyone:&T){
T::sleep();
}
使用:
let stu=Student{name:"YSS".to_string()};
Student::who(&stu);
Student::doing_at_night(&stu);
需要注意的是,trait bounds提供了对泛型参数的约束导致对传入的泛型类型有了一定的要求,只有符合泛型约束的类型才能正确使用泛型代码。
trait bounds除了可以像上述那样指定以外,还可以把泛型约束单独提出来放置到返回值之后{}之前的where语句中(多个泛型参数","分割),这在约束较长或者泛型参数较多的情况下能够提高代码可读性。
上述例子可改写如下:
fn who<T>(anyone: &T)
where
T: Person,
{
println!("I'm {}", anyone.get_name());
}
fn doing_at_night<T>(anyone: &T)
where
T: Person,
{
T::sleep();
}
类型上的trait bounds:
struct Foo<T:Display>{
bar:T
}
或
struct Foo<T> where T:Display{
bar:T
}
这样约束后,实例化结构体Foo时,bar只能是实现了Display trait的实例。
泛型实现上的trait bounds:
trait Eatable{
fn eat(&self);
}
#[derive(Debug)]
struct Food<T>(T);
impl<T:Debug> Eatable for Food<T>{
fn eat(&self) {
println!("Eating{:?}",self);
}
}
或
impl<T> Eatable for Food<T>where T:Debug{
fn eat(&self) {
println!("Eating{:?}",self);
}
}
特征区间组合
我们还可以使用“+”为泛型指定多个特征区间,例如:
trait Eat{
fn eat(&self){
println!("eat");
}
}
trait Code{
fn code(&self){
println!("code");
}
}
trait Sleep{
fn sleep(&self){
println!("sleep");
}
}
fn coder_life <T:Eat+Code+Sleep> (coder:T){
coder.eat();
coder.code();
coder.sleep();
}
impl特征区间
对于涉及到堆分配或无法用具体类型表示约束的类型(例如闭包),我们可以使用impl来指定特征区间:
fn lazy_adder(a:u32,b:u32)->impl Fn()->u32{
move||a+b
}
如果用普通trait bounds的话,编译器会报如下错误:
fn lazy_adder<T:Fn()->u32>(a:u32,b:u32)->T{
move||a+b
}
error[E0308]: mismatched types
--> src/main.rs:106:5
|
105 | fn lazy_adder<T:Fn()->u32>(a:u32,b:u32)->T{
| - this type parameter - expected `T` because of return type
106 | move||a+b
| ^^^^^^^^^ expected type parameter `T`, found closure
|
= note: expected type parameter `T`
found closure `[closure@src/main.rs:106:5: 106:14]`
= help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `T`
因为闭包是堆分配的,如果返回类型不做特殊处理的话,是在栈上的变量,不会像智能指针那样指向堆分配内容,所以我们只能用impl或者用智能指针包裹,像下面这样:
fn lazy_adder(a:u32,b:u32)->Box<Fn()->u32>{
Box::from(move||a+b)
}
对返回闭包感兴趣的老哥可以看看这个帖子:
https://medium.com/journey-to-rust/closures-part-2-29536393dd92
Rust 泛型的更多相关文章
- Atitit.rust语言特性 attilax 总结
Atitit.rust语言特性 attilax 总结 1. 创建这个新语言的目的是为了解决一个顽疾:软件的演进速度大大低于硬件的演进,软件在语言级别上无法真正利用多核计算带来的性能提升.1 2. 不会 ...
- the rust book 的简单入门笔记
rust learning day 1 (2021/05/27) 学了常量,变量,数据类型,控制流,所有权 char 的宽度是4字节,一个 unicode 的宽度 控制流条件都不要括号 rust 中的 ...
- Rust语言开发
Rust开发 第一个程序 fn main() { println!("Hello, world!"); // 带!号的都是宏 并不是函数 } fn main() { let nam ...
- Rust生命周期bound用于泛型的引用
在实际编程中,可能会出现泛型引用这种情况,我们会编写如下的代码: struct Inner<'a, T> { data: &'a T, } 会产生编译错误: error[E0309 ...
- Rust中的泛型
go没有的,rust有呢~~ fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { let mut largest = li ...
- Rust语言的多线程编程
我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...
- Rust语言:安全地并发
http://www.csdn.net/article/2014-02-26/2818556-Rust http://www.zhihu.com/question/20032903 Rust是近两年M ...
- D、GO、Rust 谁会在未来取代 C?为什么?——Go语言的定位非常好,Rust语言非常优秀,D语言也不错
不要管我的地位和 D 语言创造者之一的身份.我会坦诚的回答这个问题.我熟悉 Go 和 Rust,并且知道 D 的缺点在哪里.我鼓励人们在 Rust 和 Go 社区相似身份的人,也可以提出他们诚恳的观点 ...
- Rust语言
Rust语言 https://doc.rust-lang.org/stable/book/ http://www.phperz.com/article/15/0717/141560.html Rust ...
随机推荐
- Linux Nvidia显卡驱动安装
1 概述 因为某些需要需要在Linux上安装显卡驱动,这里记录一下安装过程. 2 环境 Manjaro RTX 2060 3 下载驱动安装包 到官网上搜索下载即可,可以戳这里: 选择自己的显卡型号即可 ...
- JVM调优基础到进阶
GC和GC Tuning GC的基础知识 1.什么是垃圾 C语言申请内存:malloc free C++: new delete c/C++ 手动回收内存 Java: new ? 自动内存回收,编程上 ...
- Neo4j/cypher学习笔记与学习建议
简介 本笔记的主要内容是 cypher 查询语言的编写与使用. 笔记主要整理自w3cschool上的neo4j教程以及Neo4j中文网所提供的cypher中文文档,此外还包括少量从其他个人博客与官方手 ...
- 模拟退火算法(1)Python 实现
1.模拟退火算法 模拟退火算法借鉴了统计物理学的思想,是一种简单.通用的启发式优化算法,并在理论上具有概率性全局优化性能,因而在科研和工程中得到了广泛的应用. 退火是金属从熔融状态缓慢冷却.最终达到能 ...
- ASP.NET Core五种Filter
Authorization Filter Authorization是五种Filter中优先级最高的,通常用于验证Request合不合法,不合法后面就直接跳过. 权限控制器过滤器,可以通过Authon ...
- 《机器学习Python实现_10_06_集成学习_boosting_gbdt分类实现》
一.利用回归树实现分类 分类也可以用回归树来做,简单说来就是训练与类别数相同的几组回归树,每一组代表一个类别,然后对所有组的输出进行softmax操作将其转换为概率分布,然后再通过交叉熵或者KL一类的 ...
- Unity基础-脚本生命周期
理解Unity脚本的生命周期对游戏开发很重要,这篇文章对生命周期做一个记录和总结.Unity的脚本生命周期(消息),也就是在脚本运行时,自动并且按顺序执行的一系列函数.在unity官网中有对生命周期详 ...
- hdu 1298 字典树 + DFS (模拟T9文本输入)
题意: 给你一些按键顺序,让你输出每一步中概率最大的那个单词,这里的概率计算方 法好好看看别弄错了,一开始就是因为弄错了,各种wa,比如 abc 1 ,ab 1,那么 ab 的概率就是2 ...
- hdu5256序列变换(非递减子序列)
题意(中文直接粘吧)序列变换 Problem Description 我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元 ...
- UVA11137(立方数之和)
题意: 给你一个n(<=10000),问他如果由立方数之和组成,那么有多少种方法? 思路: 一个地推公式,d[i][j] 表示用不大于i的数字去组合j这个数字有多少种方 ...