[Rust] 可迭代类型, 迭代器, 如何正确的创建自定义可迭代类型
在 Rust 中, for 语句的执行依赖于类型对于 IntoIterator
的实现, 如果某类型实现了这个 trait, 那么它就可以直接使用 for 进行循环.
直接实现
在 Rust 中, 如果一个类型实现了 Iterator
, 那么它会被同时实现 IntoIterator
, 具体逻辑是返回自身, 因为自身就是迭代器.
但是如果自身就是迭代器的话, 就意味着自身必须存储迭代状态, 例如当前迭代的位置. 如果是这样的话, 迭代器就只能被使用一次. 况且自身直接被传入 into_iter
方法后, 所有权被转移, 该对象就无法被再次使用了.
定义类型本身:
struct IntRange {current: i32,step: i32,end: i32
}
直接为其实现迭代器:
impl Iterator for IntRange {type Item = i32;fn next(&mut self) -> Option<Self::Item> {if self.current == self.end {return None;} else {let current = self.current;self.current += self.step;return Some(current);}}
}
使用该类型:
let range = IntRange { current: 0, step: 1, end: 10 };
for value in range {println!("v: {}", value);
}
所以结论是, 如果你的类型是一次性用品, 你可以直接对其实现 Iterator
手动实现迭代器
如果你向手动实现类似于容器的东西, 那么它当然不是一次性的. 我们应该仿照 Rust 中对切片的迭代器实现.
- 同时实现会转移所有权和不会转移所有权的两个迭代器
- 对
self
和&self
都实现IntoIterator
, 这样就可以做不转移所有权的迭代了
类型本身:
struct IntRange {step: i32,end: i32
}
两个迭代器:
struct IntRangeIter<'a> {range: &'a IntRange,current: i32,
}struct IntRangeIntoIter {range: IntRange,current: i32,
}
两个迭代器实现:
impl Iterator for IntRangeIter<'_> {type Item = i32;fn next(&mut self) -> Option<Self::Item> {if self.current == self.range.end {return None;} else {let current = self.current;self.current += self.range.step;return Some(current);}}
}impl Iterator for IntRangeIntoIter {type Item = i32;fn next(&mut self) -> Option<Self::Item> {if self.current == self.range.end {return None;} else {let current = self.current;self.current += self.range.step;return Some(current);}}
}
实现返回两种迭代器的 IntoIterator
:
impl<'a> IntoIterator for &'a IntRange {type Item = i32;type IntoIter = IntRangeIter<'a>;fn into_iter(self) -> Self::IntoIter {IntRangeIter {range: self,current: 0}}
}impl IntoIterator for IntRange {type Item = i32;type IntoIter = IntRangeIntoIter;fn into_iter(self) -> Self::IntoIter {IntRangeIntoIter {range: self,current: 0}}
}
使用它:
let range = IntRange { step: 1, end: 10 };// 可以使用引用来进行 for 循环
for value in &range {println!("v: {}", value);
}// 也可以直接对其进行 for 循环
for value in range {println!("v: {}", value);
}
切片对迭代的实现
我们知道, Rust 的切片有一个 iter
方法, 其实它就相当于对当前切片的引用调用 into_iter
.
其实, 在调用切片引用的 into_iter
方法时, 本质上就是调用的其 iter
方法. 方法的实现是在 iter
内的.
let v = vec![1, 2, 3];// 下面两个调用是等价的
let iter1 = v.iter();
let iter2 = (&v).into_iter();
如果你希望实现迭代变量可变的迭代器, 还可以为 &mut T
实现 into_iter
, 当然, Rust 内部对于切片的实现, 也是这样的:
let mut v = vec![1, 2, 3];// 下面两个调用是等价的
let mutIter = v.iter_mut();
let mutIter = (&mut v).into_iter();
总结
两种类型:
-
对于一次性使用的类型, 可以直接对其实现迭代器 trait.
-
对于容器, 不应该对容器本身直接实现迭代器, 而是应该单独创建迭代器类型, 然后对其本身实现
IntoIterator
为了方便用户使用, 调用之间的实现应该是这样:
- 实现
T
的IntoIterator
- 实现
&T
的iter
函数, 返回借用的迭代器. - 实训
&mut T
的iter_mut
函数, 返回可变借用的迭代器. - 对
&T
和&mut T
实现into_iter
函数, 并在内部调用刚刚实现的iter
和iter_mut
函数.
这样, 用户就可以直接调用 iter
方法获得借用的迭代器, 然后使用 map
, filter
等方法进行集合的复杂操作了
相关文章:
[Rust] 可迭代类型, 迭代器, 如何正确的创建自定义可迭代类型
在 Rust 中, for 语句的执行依赖于类型对于 IntoIterator 的实现, 如果某类型实现了这个 trait, 那么它就可以直接使用 for 进行循环. 直接实现 在 Rust 中, 如果一个类型实现了 Iterator, 那么它会被同时实现 IntoIterator, 具体逻辑是返回自身, 因为自身就是迭代器. 但是如…...
MySQL中,text,mediumtext, 和 longtext字符类型
需求 由于项目需要,需要在mysql数据库,储存长文本,长文本格式可能为markdown也可能为html。 思路 测试存入html时,字符类型为varcar 255。很明显字符长度达不到要求。数据库抛错,修改字符类型 解决方案 将原本的字…...

网页开发 JS基础
目录 JS概述 基本语法 数据类型内置方法 DOM对象 查找标签 绑定事件 操作标签 jQuery 查找标签 绑定事件 操作标签 Ajax请求 数据接口 前后端分离 ajax的使用 JS概述 一门弱类型的编程语言,属于基于对象和基于原型的脚本语言. 1 直接编写<script>console…...

如何在财税行业查找批量客户?
现在市场上代记账公司也不算少,做过这行的都知道,最初呢行业竞争不强,都是靠地推、老客户转介绍,或者长期以往的蹲守各个地区的工商注册服务中心,找那些才注册企业的老板或者创业者。但是,随着市场经济的发…...
IntelliJ IDEA详细完整安装教程
IntelliJ IDEA 是一款强大的Java集成开发环境,以下是安装和使用教程: 1. 下载IntelliJ IDEA:访问JetBrains官网(jetbrains.com),点击“Download”按钮,选择适合自己操作系统的版本进行下载。 2.…...
【.NET Core】Linq查询运算符(一)
【.NET Core】Linq查询运算符(一) 文章目录 【.NET Core】Linq查询运算符(一)一、概述二、筛选数据三、投影运算3.1 Select 3.2 SelectMany3.3 Zip3.4 Select 与 SelectMany 四、Set(设置)运算4.1 Distinct…...

Python sorted函数及用法以及如何用json模块存储数据
Python sorted函数及用法 sorted() 函数与 reversed() 函数类似,该函数接收一个可迭代对象作为参数,返回一个对元素排序的列表。 在交互式解释器中测试该函数,可以看到如下运行过程: >>> a [20, 30, -1.2, 3.5, 90, 3.…...

使用opencv将sRGB格式的图片转换为BT.2020格式【sRGB】【BT.2020】
将sRGB格式的图片转换为BT.2020格式涉及到两个步骤:首先将sRGB转换到线性RGB,然后将线性RGB转换到BT.2020。这是因为sRGB图像通常使用伽马校正,而BT.2020工作在线性色彩空间中。 从sRGB到线性RGB:sRGB图像首先需要进行伽马校正解码…...
聊天注意事项
聊天成功的核心就是双方都能舒服 有些人不会聊天是缺乏引导性 聊天聊两句话就没了 聊天要把话题引导向对方 从倾诉者变为倾听者 才能不断交流 沟通不是一个人的独角戏 每个人都渴望被理解 要注意倾听别人说的话 不要只顾自己说一大堆,别人都瞌睡了 不要查户口式问…...

12.5 作业
1, 以下是一个简单的比喻,将多态概念与生活中的实际情况相联系: 比喻:动物园的讲解员和动物表演 想象一下你去了一家动物园,看到了许多不同种类的动物,如狮子、大象、猴子等。现在,动物园里有…...

深入理解指针3
hello,各位小伙伴,本篇文章跟大家一起继续深入学习指针,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 如果本篇文章对你有帮助,还请各位点点赞!!! 话不多说&am…...
大数据环境下在线考试系统安全策略研究
摘 要 随着云计算、物联网、电子商务、企业信息化等的飞速发展,以及智能终端和各种检测、感应设备的普及和建设,全球逐渐进入信息化、网络化,由此产生了指数爆炸般的数据增长,一个大规模生产、分享和应用的数据的时代正在开启&am…...

Python中程序的异常处理
Python程序一般对输入有一定要求,担当实际输入不满足程序要求时,可能会产生程序的运行错误。Python语言使用的保留太容易try和except进行异常处理! try: 语句块1 except: 语句块2 语句块1是正常执行的程序内容,当这个语句块发生异…...

有趣的代码——有故事背景的程序设计3
这篇文章再和大家分享一些有“背景”的程序设计,希望能够让大家学到知识的同时,对编程学习更感兴趣,更能在这条路上坚定地走下去。 目录 1.幻方问题 2.用函数打印九九乘法表 3.鸡兔同笼问题 4.字数统计 5.简单选择排序 1.幻方问题 幻方又…...

聚观早报 |国行PS5轻薄版开售;岚图汽车11月交付7006辆
【聚观365】12月2日消息 国行PS5轻薄版开售 岚图汽车11月交付7006辆 比亚迪推出12月限时优惠 特斯拉正式交付首批Cybertruck 昆仑万维发布「天工 SkyAgents」平台 国行PS5轻薄版开售 索尼最新的PlayStation5主机(CFI-2000型号组-轻薄版)国行版本正…...

Kafka 保证消息消费全局顺序性
当有消息被生产出来的时候,如果没有指定分区或者指定 key ,那么消费会按照【轮询】的方式均匀地分配到所有可用分区中,但不一定按照分区顺序来分配 我们知道,在 Kafka 中消费者可以订阅一个或多个主题,并被分配一个或多…...
3分钟在CentOS 7上离线安装Docker
在CentOS 7上离线安装Docker的详细步骤如下: 环境检查和准备 检查内核版本:Docker要求系统为64位且内核版本至少为3.10。使用命令uname -r查看内核版本。 检查CentOS版本:通过命令cat /etc/redhat-release查看版本信息。 更新yum包࿰…...

GaussDB数据库SQL系列-触发器
目录 一、前言 二、触发器概念 三、GaussDB数据库中的触发器 1、语法格式 2、创建步骤 3、注意事项 4、附:表和视图上支持的触发器种类 四、GaussDB数据库中的示例 示例一、在GaussDB数据库中创建一个触发器,以便在插入新记录时自动将记录的创建…...

网工学习10-IP地址
一、IP地址概念 IP地址是一个32位的二进制数,它由网络ID和主机ID两部份组成,用来在网络中唯一的标识的一台计算机。网络ID用来标识计算机所处的网段;主机ID用来标识计算机在网段中的位置。IP地址通常用4组3位十进制数表示,中间用…...

二百零八、Hive——HiveSQL异常:Select查询数据正常,但SQL语句加上group by查询数据为空
一、目的 在HiveSQL的DWD层中,需要对原始数据进行去重在内的清洗,结果一开始其他数据类型的清洗工作都正常,直到碰到转向比数据。 一般的SQL查询有数据,但是加上group by以后就没数据; 一般的SQL查询有数据…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...