rust迭代器
迭代器用来遍历容器。
迭代器就是把容器中的所有元素按照顺序一个接一个的传递给处理逻辑。
Rust中的迭代器
标准库中定义了Iterator特性
trait Iterator {type Item;fn next(&mut self) -> Option<Self::Item>;
}
实现了Iterator特性的结构体就是迭代器。
很多类型都有iter()方法,返回一个Iter结构体,该结构体实现了Iterator特性。
一、创建迭代器
Rust中有三种类型的迭代器。
从容器创建迭代器有三种方法。
iter() 返回一个只读可重入迭代器,迭代器元素的类型为 &T
iter_mut() 返回一个可写可重入迭代器,迭代器元素的类型为 &mut T
into_iter() 返回一个只读不可重入迭代器,迭代器元素的类型为 T
(一)iter()
返回一个只读可重入迭代器,迭代器元素的类型为&T。
例子
fn main() {let names = vec!["简单教程", "简明教程", "简单编程"];let name = names.iter();println!("{:?}", names);
}
(二)iter_mut()
返回一个可写可重入迭代器,迭代器元素的类型为&mut T。
例子
fn main() {let mut names = vec!["简单教程", "简明教程", "简单编程"];let name = names.iter_mut();println!("{:?}", names);
}
(三)into_iter()
返回一个只读不可重入迭代器,迭代器元素的类型为T
它会把容器的值移动到迭代器中。
iter_into()之后的容器不可重用。
例子
fn main() {let mut names = vec!["简单教程", "简明教程", "简单编程"];let name = names.into_iter();println!("{:?}", name);//println!("{:?}", names);//去掉注释会编译错误
}
二、使用迭代器
(一)返回迭代器元素个数
count()
消耗迭代器,计算迭代次数并返回它。
此方法将反复调用next(),直到遇到None,并返回它看到Some的次数。 请注意,即使迭代器没有任何元素,也必须至少调用一次next()
溢出行为
该方法无法防止溢出,因此对具有超过usize::MAX个元素的迭代器的元素进行计数会产生错误的结果或panics。
如果启用了调试断言,则将保证panic。
Panics
如果迭代器具有多个usize::MAX元素,则此函数可能为panic。
例子
let a = [1, 2, 3];
assert_eq!(a.iter().count(), 3);
(二)访问迭代器元素
nth(n)
返回迭代器的第n个元素。
计数从零开始,因此nth(0) 返回第一个值,nth(1) 返回第二个值,依此类推。
请注意,所有先前的元素以及返回的元素都将从迭代器中消耗。这意味着前面的元素将被丢弃,并且在同一迭代器上多次调用nth(0)将返回不同的元素。
如果n大于或等于迭代器的长度,则nth()将返回None。
例子
let a = [1, 2, 3];
assert_eq!(a.iter().nth(1), Some(&2));
多次调用nth() 不会回退迭代器:
let a = [1, 2, 3];
let mut iter = a.iter();
assert_eq!(iter.nth(1), Some(&2));
assert_eq!(iter.nth(1), None);
如果n大于或等于迭代器的长度,则返回None:
let a = [1, 2, 3];
assert_eq!(a.iter().nth(10), None);
last()
消耗迭代器,返回最后一个元素。
此方法将评估迭代器,直到返回None。 这样做时,它会跟踪当前元素。 返回None之后,last() 将返回它看到的最后一个元素。
例子
let a = [1, 2, 3];
assert_eq!(a.iter().last(), Some(&3));
(三)遍历迭代器
1.使用next()方法遍历容器
例子
fn main() {let a = [10,20,30];let mut iter = a.iter(); // 从一个数组中返回迭代器println!("{:?}",iter);//使用next() 方法返回迭代器中的下一个元素println!("{:?}",iter.next());println!("{:?}",iter.next());println!("{:?}",iter.next());println!("{:?}",iter.next());
}
编译运行结果如下
Iter([10, 20, 30])
Some(10)
Some(20)
Some(30)
None
2.使用for循环遍历
手动调用next()太麻烦了,推荐使用for循环来使用迭代器。
(1)iter()
例子
fn main() {let names = vec!["简单教程", "简明教程", "简单编程"];for name in names.iter() {println!("{}", name);}println!("{:?}", names);
}
for name in &names
实际上等价于
for name in names.iter()
(2)iter_mut()
例子
fn main() {let mut names = vec!["简单教程", "简明教程", "简单编程"];for name in names.iter_mut() {println!("{}", name);}println!("{:?}", names);
}
for name in &mut names
实际上等价于
for name in names.iter_mut()
(3)into_iter()
例子
fn main() {let names = vec!["简单教程", "简明教程", "简单编程"];for name in names.into_iter() {println!("{}", name);}//println!("{:?}", names); //去掉注释会编译错误
}
for name in names
实际上等价于
for name in names.into_iter()
(四)迭代器转换成容器
collect()
将迭代器转换为容器。
使用collect()的最基本模式是将一个容器转换为另一个容器。 在一个容器上调用iter,进行了一堆转换,最后调用collect()。
由于collect()非常通用,因此可能导致类型推断问题。 因此,要指定类型或使用turbofish语法。
例子
let a = [1, 2, 3];
let doubled: Vec<i32> = a.iter().map(|&x| x * 2).collect();
assert_eq!(vec![2, 4, 6], doubled);
使用自动推断类型
let a = [1, 2, 3];
let doubled: Vec<_> = a.iter().map(|&x| x * 2).collect();
assert_eq!(vec![2, 4, 6], doubled);
使用turbofish
let a = [1, 2, 3];
let doubled = a.iter().map(|x| x * 2).collect::<Vec<i32>>();
assert_eq!(vec![2, 4, 6], doubled);
_ 与turbfish一起使用:
let a = [1, 2, 3];
let doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>();
assert_eq!(vec![2, 4, 6], doubled);
(五)迭代器转换
map()方法可以转换迭代器
创建一个迭代器,该迭代器每个元素是由原迭代器元素应用闭包得到。
可以这样考虑map(): 如果您有一个元素类型为A的迭代器,您想要元素类型为B的迭代器,则可以使用map(),传递一个把A转成B的闭包。
例子
let a = [1, 2, 3];
let mut iter = a.iter().map(|x| 2 * x);
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), Some(6));
assert_eq!(iter.next(), None);
如果您正在做某种副作用,请首选for而不是map():
不要这样做:
(0..5).map(|x| println!("{x}"));// 它甚至不会执行,因为它很懒。Rust会就此警告您。
而是用:
for x in 0..5 {println!("{x}");
}
flat_map()
创建一个迭代器,其工作方式类似于map,但它会将嵌套的结构展平。
map非常有用,但仅当闭包产生值时才使用。 如果它产生一个迭代器,则存在一个额外的间接层。flat_map() 将自行删除这个间接层。
您可以把flat_map(f) 视为map(f).flatten()。
map的闭包为每个元素返回一个值,而flat_map ()的闭包为每个元素返回一个迭代器。
例子
let words = ["alpha", "beta", "gamma"];
// chars() 返回一个迭代器
let merged: String = words.iter().flat_map(|s| s.chars()).collect();
assert_eq!(merged, "alphabetagamma");
flatten()
创建一个去掉嵌套层的迭代器。比如二维向量变一维向量
例子
let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
let flattened = data.into_iter().flatten().collec::<Vec<u8>>();
assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]);let words = ["alpha", "beta", "gamma"];
// chars() 返回一个迭代器
let merged: String = words.iter().map(|s| s.chars()).flatten().collect();
assert_eq!(merged, "alphabetagamma");
您也可以用flat_map()来重写它
let words = ["alpha", "beta", "gamma"];
// chars() 返回一个迭代器
let merged: String = words.iter().flat_map(|s| s.chars()).collect();
assert_eq!(merged, "alphabetagamma");
展平一次只能删除一层嵌套:
let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
let d2 = d3.iter().flatten().collect::<Vec<_>>();
assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]);
let d1 = d3.iter().flatten().flatten().collect::<Vec<_>>();
assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]);
在这里,我们看到flatten()仅删除了一层嵌套。三维数组变二维而不是一维。要获得一维,您必须再次flatten()。
(六)enumerate
创建一个迭代器,该迭代器元素是(i, val),其中i是当前迭代索引,val是迭代器返回的值。
enumerate()保持其计数为usize。
溢出行为
该方法无法防止溢出,因此枚举多个usize::MAX元素会产生错误的结果或panics。 如果启用了调试断言,则将保证panic。
Panics
如果要返回的索引将溢出usize,则返回的迭代器可能为panic。
例子
let a = ['a', 'b', 'c'];
let mut iter = a.iter().enumerate();
assert_eq!(iter.next(), Some((0, &'a')));
assert_eq!(iter.next(), Some((1, &'b')));
assert_eq!(iter.next(), Some((2, &'c')));
assert_eq!(iter.next(), None);
(七)逆转迭代器
rev
反转迭代器的方向。
通常,迭代器从左到右进行迭代。 使用rev() 之后,迭代器将改为从右向左进行迭代。
例子
let a = [1, 2, 3];
let mut iter = a.iter().rev();
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), None);
(八)截取迭代器
take(n)
创建一个迭代器,它的元素是原迭代器的前n个元素。如果原迭代器元素数小于n,则返回原迭代器所有元素。
例子
let a = [1, 2, 3];
let mut iter = a.iter().take(2);
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), None);
let v = [1, 2];
let mut iter = v.into_iter().take(5);
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);
(九)其他
max
返回迭代器的最大元素。
如果几个元素最大相等,则返回最后一个元素。如果迭代器为空,则返回None。
请注意,由于NaN不可比较,f32/f64没有实现Ord。 您可以使用Iterator::reduce解决此问题:
assert_eq!([2.4, f32::NAN, 1.3].into_iter().reduce(f32::max).unwrap(),2.4);
例子
let a = [1, 2, 3];
let b: Vec = Vec::new();
assert_eq!(a.iter().max(), Some(&3));
assert_eq!(b.iter().max(), None);
min
返回迭代器的最小元素。
如果几个元素相等地最小,则返回第一个元素。 如果迭代器为空,则返回None。
请注意,由于NaN不可比较,f32/f64没有实现Ord。您可以使用Iterator::reduce解决此问题:
assert_eq!([2.4, f32::NAN, 1.3].into_iter().reduce(f32::min).unwrap(),1.3);
例子
let a = [1, 2, 3];
let b: Vec = Vec::new();
assert_eq!(a.iter().min(), Some(&1));
assert_eq!(b.iter().min(), None);
sum
对迭代器的元素求和。
获取每个元素,将它们添加在一起,然后返回结果。
空的迭代器将返回该类型的零值。
sum()可用于对任何实现Sum的类型求和,包括Option和Result。
Panics
当调用sum() 并返回原始整数类型时,如果计算溢出并且启用了调试断言,则此方法将为panic。
例子
let a = [1, 2, 3];
let sum: i32 = a.iter().sum();
assert_eq!(sum, 6);
相关文章:
rust迭代器
迭代器用来遍历容器。 迭代器就是把容器中的所有元素按照顺序一个接一个的传递给处理逻辑。 Rust中的迭代器 标准库中定义了Iterator特性 trait Iterator {type Item;fn next(&mut self) -> Option<Self::Item>; }实现了Iterator特性的结构体就是迭代器。 很多类…...
软件定制开发的优势与步骤|APP搭建|小程序
软件定制开发的优势与步骤|APP搭建|小程序 定制开发的优势: 1. 满足特定需求:定制开发可以根据客户的实际需求进行设计和开发,使得软件系统能够更好地满足客户的业务目标。 2. 优化用户体验:通过深入了解客户的需求,定…...
ERR_CONNECTION_REFUSED等非标准的HTTP错误状态码原因分析和解决办法
文章目录 一、DNS Resolution Failed1,DNS服务器故障2,DNS配置错误3,DNS劫持4,域名过期-5,其他网络问题 二、ERR_CONNECTION_REFUSED-"ERR_CONNECTION_REFUSED" 错误可能有多种原因 三、ERR_SSL_PROTOCOL_ER…...
瀑布流 - Vue3基于Grid布局简单实现一个瀑布流组件
瀑布流 - Vue3基于Grid布局简单实现一个瀑布流组件 前言 在学习Grid布局之时,我发现其是CSS中的一种强大的布局方案,它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,在刷某书和某宝首页时&…...
ES6面试题总结
1. 谈谈你对 ES6 的理解,为什么要学习es6? ES6是新一代的JS语言标准,对分JS语言核心内容做了升级优化,规范了JS使用标准,新增了JS原生方法,使得JS使用更加规范,更加优雅,更适合大型应用的开发。学习ES6是成…...
mybatisplus,jdbc 批量插入
1.测试用例 项目中遇到在做导入号码的时候我们会用到批量导入,提高入库的速度。接下来我们以10000条为测试用例。 1.1 批量执行sql语句 当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库…...
如何使用IP归属地查询API来追踪网络活动
引言 在当今数字化世界中,了解网络活动的源头和位置对于网络安全、市场研究和用户体验至关重要。IP归属地查询API是一种强大的工具,可以帮助您追踪网络活动并获取有关IP地址的重要信息。本文将探讨如何使用IP归属地查询API来追踪网络活动,以…...
【SQL】S0 系列博文大纲
系列博文大纲 SQL 学习环境建议系列博文相关书籍系列博文大纲阶段进展 SQL 学习环境建议 对于 SQL 语言的学习,博主本地使用:MySQL DataGrip; MySQL 提供本地数据库服务; DataGrip IDE,承担编程运行测试任务…...
2023年8月体育用品行业数据分析(京东数据产品)
当前,亚运会临近,这也带动了国民对体育消费的热情,体育产品内销逐渐旺盛,“亚运经济”红利开始显现。鲸参谋数据显示,今年8月份,京东平台上体育用品行业的销量为185万,同比增长2%;销…...
国内高校镜像网站
国内各大高校开源镜像站 排名不分前后 清华大学:https://mirrors.tuna.tsinghua.edu.cn/ 北京大学:https://mirrors.pku.edu.cn/ 北京外国语大学:http:// https://mirrors.bfsu.edu.cn/ 北京理工大学:https://mirrors.bit.e…...
Linux安装kafka-manager
相关链接https://github.com/yahoo/kafka-manager/releases kafka-manager-2.0.0.2下载地址 百度云链接:https://pan.baidu.com/s/1XinGcwpXU9YBF46qkrKS_A 提取码:tzvg 一、安装部署 1.把kafka-manager-2.0.0.2.zip拷贝到目录 /opt/app/elk 2.解压…...
MYSQL索引——B+树讲解
B-/B树看 MySQL索引结构 B-树 B-树,这里的 B 表示 balance( 平衡的意思),B-树是一种多路自平衡的搜索树.它类似普通的平衡二叉树,不同的一点是B-树允许每个节点有更多的子节点。下图是 B-树的简化图. B-树有如下特点: 所有键值分布在整颗树中; 任何一…...
VB将十进制整数转换成16进制以内的任意进制数
VB将十进制整数转换成16进制以内的任意进制数 数值转换,能够将十进制整数转换成16进制以内的任意进制数 Private Function DecToN(ByVal x%, ByVal n%) As StringDim p() As String, y$, r%p Split("0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F", ",")I…...
基于SpringBoot+Vue的宠物领养饲养交流管理平台设计与实现
前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻…...
【图像去噪】【TGV 正则器的快速计算方法】通过FFT的总(广义)变化进行图像去噪(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
windbg调试句柄问题
这里写自定义目录标题 winform,句柄资源不够强,程序crash句柄主程序c程序,加载的插件是c# dll,这时候如何用windbg调试dll库如果查看句柄和对象的关系!handle 怎么能知道哪个句柄是Form对话框的句柄如何查看句柄对应的类对象 winf…...
9月13-14日上课内容 第三章 ELK日志分析系统及部署实例
本章结构 ELK日志分析系统简介 ELK日志分析系统分为 Elasticsearch Logstash Kibana 日志处理步骤 1.将日志进行集中化管理 2.将日志格式化(Logstash) 并输出到Elasticsearch 3.对格式化后的数据进行索引和存储 (Elasticsearch) 4.前端数据的展示(Kibana) Elasticsearch介…...
服务器端应用的安装
前言:相信看到这篇文章的小伙伴都或多或少有一些编程基础,懂得一些linux的基本命令了吧,本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python:一种编程语言&…...
关于硬盘质量大数据分析的思考
近日,看到Backblaze分享了一遍关于硬盘运行监控数据架构的文章,觉得挺有意义的,本文就针对这方面跟大家聊聊。 作为一家在2021年在美国纳斯达克上市的云端备份公司,Backblaze一直保持着对外定期发布HDD和SSD的故障率稳定性质量报告…...
RK3568核心板分区空间不足,如何修改分区大小?
在对评估板进行开发验证时,时常会遇到根目录空间不足的情况,而在其他分区又有冗余空间,这时则需要对分区大小重新进行分配,合理化利用分区空间。 本文将基于HD-RK3568-IOT评估板主要讲解如何修改eMMC分区大小。 1. 分区表介绍…...
Rk3566 yolov5部署(一)Ubuntu系统镜像烧录与串口调试实战
1. 准备工作:硬件与软件清单 在开始RK3566开发板的Ubuntu系统镜像烧录之前,我们需要准备好必要的硬件和软件工具。我刚开始接触这块开发板时,就因为漏掉了几个小配件耽误了一整天时间,所以特别提醒大家要仔细检查以下清单。 硬件部…...
告别吃灰!用Kindle打造唐诗宋词字帖屏保的完整避坑指南(含繁简转换技巧)
用Kindle打造唐诗宋词字帖屏保的完整指南 作为一个长期关注数字阅读与传统文化的深度用户,我发现Kindle的墨水屏特性非常适合展示书法字帖。这种将现代科技与传统艺术结合的方式,不仅能提升设备使用率,还能在日常碎片时间中培养书写习惯。本文…...
uniapp日期处理全攻略:获取某月首尾日、近七天日期等实用技巧
Uniapp日期处理实战:从基础格式化到高级业务场景解决方案 在移动应用开发中,日期处理几乎贯穿所有业务场景。无论是电商平台的限时抢购、医疗应用的预约挂号,还是企业系统的报表统计,精准高效的日期操作都是保障业务逻辑完整性的关…...
工业质检新突破:如何用GLAD扩散模型实现高精度无监督异常检测(附MVTec-AD实测)
工业质检革命:GLAD扩散模型如何重塑无监督缺陷检测 在制造业智能化转型浪潮中,工业质检环节正经历着从人工目检到AI视觉的范式转移。传统基于规则或监督学习的检测系统面临标注成本高、泛化能力弱等痛点,而无监督异常检测技术凭借"零样本…...
【大模型调优】彻底洗掉论文“机器味”:DeepSeek/Kimi/豆包专属降AI指令与保姆级工作流
很多时候大学生写论文逻辑太严谨、话术太规范,反而会导致AI率过高,且一旦AI率过高,轻则退回重改,重则取消答辩资格,这后果谁都担不起。 为了帮大家有效降低aigc率,这周我专门针对目前市面上最主流的三款大…...
5年java开发经验总结面试题-内含完整答案
1、讲讲IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞。 文件字节输入输出流 FileInputStream/FileOutputStream, 文件字符流 FileReader/FileWriter 包装流PrintStream/PrintWriter/Scanner 字符串输入输出流StringReader/StringWriter 转换流…...
保姆级教程:用Docker Compose一键部署带汉化和HTTPS的n8n,并配置反向代理(Nginx)
企业级n8n自动化平台全栈部署实战:从容器编排到安全加固 在数字化转型浪潮中,自动化工作流平台已成为企业降本增效的核心基础设施。n8n作为GitHub上增长最快的开源自动化工具之一,凭借其可视化编排能力和400节点生态,正在重塑企业…...
CST仿真设计:反射透射性线圆转换与线线转换实战案例及录屏教程
cst仿真设计 反射透射性线圆转换,线线转换 案例与录屏打开CST刚打开模板栏是不是总盯着默认的几个空模板发呆?今天咱们整点新手入门但能快速装逼朋友圈或者中期报告材料的活——反射透射都能玩的偏振转换超表面(Metasurface)&…...
效率飙升:用快马生成可复用的wsl环境配置脚本,告别重复劳动
最近在团队协作和更换设备时,经常需要重复配置WSL开发环境,每次都要手动执行一堆命令,不仅耗时还容易遗漏步骤。经过多次实践,我总结出一套用脚本自动化配置的方法,现在通过InsCode(快马)平台就能快速生成可复用的环境…...
LangChain4j vs Spring AI:Java AI 框架技术选型深度对比与生产落地指南
LangChain4j vs Spring AI:Java AI 框架技术选型深度对比与生产落地指南 摘要:当 Java 团队建设 AI 应用时,真正困难的通常不是“能否调通模型”,而是“如何把 Prompt、RAG、工具调用、可观测性、限流熔断、灰度发布、权限隔离与业务系统稳定地耦合起来”。本文不再停留在 …...
