rust 泛型、多态

一,泛型

1,泛型函数

下面是一个手动实现vec翻转的例子:

fn vector_reverse<T:Clone> (v:&Vec<T>)->Vec<T>{let mut ans = Vec::new();let mut i = v.len();loop {if i==0{break;}i-=1;ans.push(v[i].clone());}return ans;
}

这里一共有3处类型参数T

第一个vector_reverse<T:Clone>表示这个泛型函数的的参数就是T

第二个v:&Vec<T>表示入参是T类型的vec

第三个->Vec<T>表示返回值是T类型的vec

也可以使用多个模板参数:

fn f<T:Clone, S:Copy> (v:&Vec<T>,s:&Vec<S>)->i32
{return 0;
}

2,特征约束

(1)特征约束

vector_reverse的例子中,要求模板参数T具有Clone特征,这就是一个特征约束。

泛型函数要保证自身是能编译的,而不取决于调用代码。所以,泛型函数内部对T的约束条件,都通过指明T所包含的trait的方式进行说明。

(2)多重约束

如果T需要多个trait,采用加号把trait连接起来。

(3)where

如果特征约束比较多,为了不影响阅读,可以把约束提到函数头的末尾:

fn f<T, S> (v:&Vec<T>,s:&Vec<S>)->i32where T:Clone, S:Copy
{return 0;
}

(4)子特征的约束推导出父特征

fn f2<T:Ord+Clone>(arr:Vec<T>)->T{if(arr[0]==arr[1]){return arr[1].clone();}return arr[0].clone();
}

Ord特征中并没有eq函数,但是Ord特征间接继承了PartialOrd,所以有Ord特征的类型肯定是可以使用==的。

(5)模板类型的默认特征约束

对于绝大部分trait,模板类型都是默认不包含该trait的,需要特征约束才能说明该类型具有该trait。

而Sized是个反例,模板类型是默认包含Sized这个特征的,需要 ?Sized 才能说明可以不具有该特征。

pub trait Borrow<Borrowed: ?Sized> {
......
}

(6)trait类型的入参

fn exec(x:impl Display){print!("{}",x);
}fn main() {exec(6);
}

这是一个语法糖,等价于:

fn exec<T:Display>(x:T){print!("{}",x);
}

3,泛型数据结构

数据结构要想好用,都得是泛型的。

无论是c++ STL还是rust std,里面所有的数据结构都是泛型的,c++和rust的结构体也类似,可以是泛型的也可以是非泛型的。

(1)泛型结构体

例如 Vec

pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {buf: RawVec<T, A>,len: usize,
}

(2)泛型结构体实现trait的偏特化实现

trait VecEx {fn get_zeros_num(&self) -> i32;
}
impl VecEx for Vec<i32> {fn get_zeros_num(&self) -> i32{let mut ans = 0;for i in 0..self.len() {if (self[i] == 0) {ans+=1;}}return ans;}
}

(3)泛型结构体实现trait的泛型实现、带type的特征约束

use std::ops::Sub;
trait VecEx {fn get_zeros_num(&self) -> i32;
}
impl<T:Clone+Sub<Output=T>+PartialEq> VecEx for Vec<T> {fn get_zeros_num(&self) -> i32{let mut ans = 0;for i in 0..self.len() {if (self[i] == self[0].clone() - self[0].clone()) {ans+=1;}}return ans;}
}

(4)泛型枚举

例如option、result

pub enum Option<T> {None,Some(T),
}pub enum Result<T, E> {Ok(T),Err(E),
}

4,常数泛型参数

和c++类型,常数也可以作为泛型参数

fn f<T:Clone,const N:usize>(arr:[T;N])->T{return arr[0].clone();
}fn main() {let x = [1,2,3];let y = [1.5,2.5];assert_eq!(f(x),1);assert_eq!(f(y),1.5);
}

作为泛型参数的常数类型,可以是所有整数类型、bool类型、char类型

5,泛型trait

给结构体实现泛型trait,会遇到一些比较复杂的情况

(1)同名且返回值相同

struct S<T, T2>
{x:T,y:T2
}
trait MyTrait<T>{fn f(&self)->i32;
}impl<T> MyTrait<T> for T{fn f(&self)->i32{-1}
}impl<T,T2> MyTrait<T> for S<T,T2>{fn f(&self)->i32{1}
}fn main() {let x=S{x:1, y:1};assert_eq!(<S<i32,i32> as MyTrait<i32>>::f(&x), 1);assert_eq!(<S<i32,i32> as MyTrait<S<i32,i32>>>::f(&x), -1);println!("end");
}

这样,实际上给S实现了2份MyTrait,必须用trait名调用函数。

(2)同名但返回值不同

参考Rc中的borrow函数

6,trait内的泛型函数

struct S{x:i32,y:f32
}trait Tr {fn f<T:Display>(x:& T){}
}impl Tr for S{fn f<T:Display>(x:& T){println!("data = {}", x);}
}fn main() {let mut s=S{x:5, y:7.7};S::f(&s.x);S::f(&s.y);
}

这个例子中,类型T是靠入参自动推导出来的。

7,trait类型的返回值

fn f()->impl Display{4546
}
fn exec<T:Display>(x:T){print!("{}",x);
}fn main() {let x = f();exec(x);
}

f可以返回任意具有Display特征的类型的数据。

8,trait对象

用dyn关键字,可以把一个trait当做一个数据类型。

前提条件:该trait的所有函数都有self参数。

struct S{x:i32
}
struct S2{y:f32
}trait Ft{fn f(&self){}fn f2(&self){}
}
impl Ft for S{fn f(&self){print!("{}",self.x);}
}
impl Ft for S2{fn f(&self){print!("{}",self.y);}
}fn exec(x: &dyn Ft) {x.f();
}fn main() {let s1 = S{x:5};let s2=S2{y:2.3};exec(&s1);exec(&s2);
}

二,隐式转换

0,背景知识

解引用操作符* 和 引用操作符&或者&mut 是相反的。

所以,只要编译器遇到*&,或者*&mut,会直接抵消掉。

只要在类型T1中定义了1个函数f,把T1数据转换成&T2或者&mut T2类型,那么就有如下的代码:

let x:T1=T1{};
let y=*x.f();

如果这个函数是deref或者deref_mut,那么就直接写成*x就行了。

可以说这是自定义解引用,也可以理解成一种隐式转换。

rust中只能自定义解引用,不能自定义引用。

1,Deref

rust语言对类型检查比较严格,不同类型之间是没有隐式转换的,除非实现了Deref这个trait

只要实现了Deref,就自动拥有了对应的隐式转换能力。

(1)定义

pub trait Deref {type Target: ?Sized;fn deref(&self) -> &Self::Target;
}

(2)示例:Vec转切片

impl<T, A: Allocator> ops::Deref for Vec<T, A> {type Target = [T];#[inline]fn deref(&self) -> &[T] {unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }}
}

使用示例:

    let c:Vec<u8>=Vec::new();let d:&[u8]=&c;

这里,&c本来是&Vec的类型,但是由于隐式转换,所以可以赋值给&[u8]类型的变量。

(3)自定义例子

use std::ops;
use ops::Deref;#[derive(Clone,Copy)]
struct S1{
}
struct S2{
}impl ops::Deref for S2{type Target = S1;fn deref(&self)->&S1{&S1{}}
}fn show(x:S1){println!("show");
}fn main() {let x:S1=S1{};show(x);let x2=S2{};show(*x2.deref());show(*x2);    println!("end");
}

这里展示了deref原始语义的例子,即*x2.deref()可以省略成*x2,这个例子中,deref就是自定义解引用,解引用完之后就变成了S1类型。

(4)隐式转换

实际上没有*操作符,deref也能发挥隐式转换的作用,但是仅限在函数参数传递过程中。

待更新

参考:

5分钟速读之Rust权威指南(二十五)Deref - 知乎

Rust-解引用-CSDN博客

2,DerefMut

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/661078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

没有外网Nginx如何配置如何开启https

判断是否支持open-ssl 在服务器执行如下命令 openssl version没有则安装open-ssl&#xff0c;由于服务器没有外网&#xff0c;可以离线安装openssl-3.0.1.tar.gz&#xff0c;我是在有网的服务器直接下载的&#xff0c;然后再上传到这台无网的服务器上 wget https://www.open…

C++内存管理与模板

C内存管理与模板 文章目录 C内存管理与模板前言&#xff1a;一.new和delete基本用法二.底层实现三.定位new四.模板4.1函数模板4.2调用选择4.3类模板4.4声明定义分离 前言&#xff1a; C的内存管理和C语言中动态内存分配是相似的&#xff0c;在这一篇我们会学到更符合面向对象的…

如何快速写出高效的软件测试用例

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前言 编写测试用例的目的就是确保测试过程全面高效、有据可查。但要编写出高效的测试用例&#…

【Django-ninja】django-ninja的hello world

django-ninja简介 Django Ninja是一个用于使用Django和Python 3.6类型提示构建API的Web框架。 主要特点&#xff1a; 易用性&#xff1a;旨在易于使用和直观。 高性能执行&#xff1a;由于Pydantic和异步支持&#xff0c;具有非常高的性能。 编码效率高&#xff1a;类型提…

鸿蒙harmony--TypeScript基础语法

把青春献给身后那座辉煌的都市&#xff0c;为了这个美梦我们付出着代价 目录 一&#xff0c;基础类型 二&#xff0c;数组 三&#xff0c;any 四&#xff0c;变量的类型注释 五&#xff0c;函数 5.1 参数类型注解 5.2 返回类型注解 5.3 匿名函数 六&#xff0c;对象类型 可选属…

APP攻防-资产收集篇反证书检验XP框架反代理VPN数据转发反模拟器

知识点 1、APP资产-抓包突破&反模拟器 2、APP资产-抓包突破&反证书检验 3、APP资产-抓包突破&反代理VPN 章节点&#xff1a; 1、APP资产-内在提取&外在抓包 2、APP逆向-反编译&删验证&重打包 3、APP安全-存储&服务&组件&注册等 专题点&…

HDFS HA 之 HA 原理

1 ZKFC解析 HA(High Availability)是HDFS支持的一个重要特性,可以有效解决Active Namenode遇到故障时,将可用的Standby节点变成新的Active状态的问题,使集群能够正常工作。目前支持冷切换和热切换两种方式。冷切换通过手动触发,缺点是不能够及时恢复集群。实际生产中以应用…

2024年【危险化学品经营单位主要负责人】报名考试及危险化学品经营单位主要负责人免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位主要负责人报名考试参考答案及危险化学品经营单位主要负责人考试试题解析是安全生产模拟考试一点通题库老师及危险化学品经营单位主要负责人操作证已考过的学员汇总&#xff0c;相对有效帮助危险化…

LeetCode:49. 字母异位词分组

49. 字母异位词分组 1&#xff09;题目2&#xff09;代码3&#xff09;结果 1&#xff09;题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs…

tkMapper 通用mapper的批量更新 批量新增 官方实现 springboot项目 依赖引入

文章目录 场景官方插件源码解析项目细节小结 场景 在许多业务场景下&#xff0c;需要对tkMapper的功能进行增强&#xff0c;需要用到批量新增和批量更新&#xff08;这里是唯一主键去更新的&#xff09;&#xff0c;许多论文博客自己写的看起来并不行&#xff0c;我们这里就采…

python爬虫3

1.异常处理&#xff0c;使代码更加健壮 静态cookie可视绕过登录的限制 快代理是一个代理平台 # https://movie.douban.com/j/chart/top_list?type5&interval_id100%3A90&action& # start0&limit20# https://movie.douban.com/j/chart/top_list?type5&int…

【LNMP】RHEL8.3安装LNMP并配置freetds连接MSSQL

【RHEL8.3安装LNMP并配置freetds连接MSSQL】 1.1.安装MYSQL(安装LNMP前置条件): rpm -ivh mysql-community-client-8.3.0-1.el8.x86_64.rpm rpm -ivh mysql-community-common-8.3.0-1.el8.x86_64.rpm rpm -ivh mysql-community-icu-data-files-8.3.0-1.el8.x86_64.rpm rpm -…

352. 闇の連鎖(树上差分,LCA)

352. 闇の連鎖 - AcWing题库 传说中的暗之连锁被人们称为 Dark。 Dark 是人类内心的黑暗的产物&#xff0c;古今中外的勇者们都试图打倒它。 经过研究&#xff0c;你发现 Dark 呈现无向图的结构&#xff0c;图中有 N 个节点和两类边&#xff0c;一类边被称为主要边&#xff…

聊聊PowerJob的ServerDeployContainerRequest

序 本文主要研究一下PowerJob的ServerDeployContainerRequest ServerDeployContainerRequest tech/powerjob/common/request/ServerDeployContainerRequest.java Data NoArgsConstructor AllArgsConstructor public class ServerDeployContainerRequest implements PowerSe…

【数据结构】 归并排序超详解

1.基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。 将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff0c;即先使每个子序列有序…

Vue3的Props

Vue 3中的props是用于接收父组件传递的数据的属性。在Vue 3中&#xff0c;props的声明发生了一些改变&#xff1a; 使用props选项来声明props。之前的版本中使用props属性来声明&#xff0c;但在Vue 3中改为使用props选项。通过TypeScript或Flow来静态类型检查props。Vue 3允许…

关于智能指针

实现自己的智能指针 //智能指针 保证能做到资源的自动释放 //利用栈上的对象出作用域自动析构的特征&#xff0c;来做到资源的自动释放的 template<typename T> class CSmartPtr { public:CSmartPtr(T *ptr nullptr):mptr(ptr) {}~CSmartPtr() { delete mptr; } privat…

Spring实现事务(一)

Spring事务 .什么是事务事务的操作Spring中事务的实现准备工作创建表创建项目,引入Spring Web, Mybatis, mysql等依赖配置文件实体类 编程式事务(手动写代码操作事务)声明式事务(利用注解自动开启和提交事务) . 什么是事务 事务是⼀组操作的集合, 是⼀个不可分割的操作 在我们…

国产校准件

国产校准件 Ceyear系列校准件是矢量网络分析仪的测试附件&#xff0c;可大幅提高矢量网络分析仪的测试精度。规格品种丰富&#xff0c;涵盖多种同轴、波导校准件&#xff0c;校准精度高&#xff0c;重复性好 功能特点 校准件 校准模块可实现更精准的测量&#xff0c;满足您的测…

RK3588平台开发系列讲解(视频篇)H.264码流结构介绍

文章目录 一、 码流查看工具二、 I帧、 P帧、 B帧三、序列四、GOP, 即关键帧间隔五、片和宏块沉淀、分享、成长,让自己和他人都能有所收获!😄 📢H.264码流结构介绍。 一、 码流查看工具 ① H.264码流查看工具: Elecard_streamEye、 Elecard StreamEye Tools、 Special…