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

[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 中对切片的迭代器实现.

  1. 同时实现会转移所有权和不会转移所有权的两个迭代器
  2. 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();

总结

两种类型:

  1. 对于一次性使用的类型, 可以直接对其实现迭代器 trait.

  2. 对于容器, 不应该对容器本身直接实现迭代器, 而是应该单独创建迭代器类型, 然后对其本身实现 IntoIterator

为了方便用户使用, 调用之间的实现应该是这样:

  1. 实现 TIntoIterator
  2. 实现 &Titer 函数, 返回借用的迭代器.
  3. 实训 &mut Titer_mut 函数, 返回可变借用的迭代器.
  4. &T&mut T 实现 into_iter 函数, 并在内部调用刚刚实现的 iteriter_mut 函数.

这样, 用户就可以直接调用 iter 方法获得借用的迭代器, 然后使用 map, filter 等方法进行集合的复杂操作了

相关文章:

[Rust] 可迭代类型, 迭代器, 如何正确的创建自定义可迭代类型

在 Rust 中, for 语句的执行依赖于类型对于 IntoIterator 的实现, 如果某类型实现了这个 trait, 那么它就可以直接使用 for 进行循环. 直接实现 在 Rust 中, 如果一个类型实现了 Iterator, 那么它会被同时实现 IntoIterator, 具体逻辑是返回自身, 因为自身就是迭代器. 但是如…...

MySQL中,text,mediumtext, 和 longtext字符类型

需求 由于项目需要&#xff0c;需要在mysql数据库&#xff0c;储存长文本&#xff0c;长文本格式可能为markdown也可能为html。 思路 测试存入html时&#xff0c;字符类型为varcar 255。很明显字符长度达不到要求。数据库抛错&#xff0c;修改字符类型 解决方案 将原本的字…...

网页开发 JS基础

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

如何在财税行业查找批量客户?

现在市场上代记账公司也不算少&#xff0c;做过这行的都知道&#xff0c;最初呢行业竞争不强&#xff0c;都是靠地推、老客户转介绍&#xff0c;或者长期以往的蹲守各个地区的工商注册服务中心&#xff0c;找那些才注册企业的老板或者创业者。但是&#xff0c;随着市场经济的发…...

IntelliJ IDEA详细完整安装教程

IntelliJ IDEA 是一款强大的Java集成开发环境&#xff0c;以下是安装和使用教程&#xff1a; 1. 下载IntelliJ IDEA&#xff1a;访问JetBrains官网&#xff08;jetbrains.com&#xff09;&#xff0c;点击“Download”按钮&#xff0c;选择适合自己操作系统的版本进行下载。 2.…...

【.NET Core】Linq查询运算符(一)

【.NET Core】Linq查询运算符&#xff08;一&#xff09; 文章目录 【.NET Core】Linq查询运算符&#xff08;一&#xff09;一、概述二、筛选数据三、投影运算3.1 Select 3.2 SelectMany3.3 Zip3.4 Select 与 SelectMany 四、Set&#xff08;设置&#xff09;运算4.1 Distinct…...

Python sorted函数及用法以及如何用json模块存储数据

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

使用opencv将sRGB格式的图片转换为BT.2020格式【sRGB】【BT.2020】

将sRGB格式的图片转换为BT.2020格式涉及到两个步骤&#xff1a;首先将sRGB转换到线性RGB&#xff0c;然后将线性RGB转换到BT.2020。这是因为sRGB图像通常使用伽马校正&#xff0c;而BT.2020工作在线性色彩空间中。 从sRGB到线性RGB&#xff1a;sRGB图像首先需要进行伽马校正解码…...

聊天注意事项

聊天成功的核心就是双方都能舒服 有些人不会聊天是缺乏引导性 聊天聊两句话就没了 聊天要把话题引导向对方 从倾诉者变为倾听者 才能不断交流 沟通不是一个人的独角戏 每个人都渴望被理解 要注意倾听别人说的话 不要只顾自己说一大堆&#xff0c;别人都瞌睡了 不要查户口式问…...

12.5 作业

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

深入理解指针3

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起继续深入学习指针&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xff01;&#xff01; 话不多说&am…...

大数据环境下在线考试系统安全策略研究

摘 要 随着云计算、物联网、电子商务、企业信息化等的飞速发展&#xff0c;以及智能终端和各种检测、感应设备的普及和建设&#xff0c;全球逐渐进入信息化、网络化&#xff0c;由此产生了指数爆炸般的数据增长&#xff0c;一个大规模生产、分享和应用的数据的时代正在开启&am…...

Python中程序的异常处理

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

有趣的代码——有故事背景的程序设计3

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

聚观早报 |国行PS5轻薄版开售;岚图汽车11月交付7006辆

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

Kafka 保证消息消费全局顺序性

当有消息被生产出来的时候&#xff0c;如果没有指定分区或者指定 key &#xff0c;那么消费会按照【轮询】的方式均匀地分配到所有可用分区中&#xff0c;但不一定按照分区顺序来分配 我们知道&#xff0c;在 Kafka 中消费者可以订阅一个或多个主题&#xff0c;并被分配一个或多…...

3分钟在CentOS 7上离线安装Docker

在CentOS 7上离线安装Docker的详细步骤如下&#xff1a; 环境检查和准备 检查内核版本&#xff1a;Docker要求系统为64位且内核版本至少为3.10。使用命令uname -r查看内核版本。 检查CentOS版本&#xff1a;通过命令cat /etc/redhat-release查看版本信息。 更新yum包&#xff0…...

GaussDB数据库SQL系列-触发器

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

网工学习10-IP地址

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

二百零八、Hive——HiveSQL异常:Select查询数据正常,但SQL语句加上group by查询数据为空

一、目的 在HiveSQL的DWD层中&#xff0c;需要对原始数据进行去重在内的清洗&#xff0c;结果一开始其他数据类型的清洗工作都正常&#xff0c;直到碰到转向比数据。 一般的SQL查询有数据&#xff0c;但是加上group by以后就没数据&#xff1b; 一般的SQL查询有数据&#xf…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...