当前位置:网站首页>【Rust 笔记】13-迭代器(上)
【Rust 笔记】13-迭代器(上)
2022-07-03 08:24:00 【phial03】
13 - 迭代器
迭代器:是可以产生一系列值的值,通常用循环来操作。
示例:
/// 返回前n位正整数的和,即第n个三角形数 fn triangle(n: i32) -> i32 { let mut sum = 0; for i in 1..n+1 { sum += i; } sum } // 通过迭代器的flod方法实现上述函数 fn triangle(n: i32) -> i32 { (1..n+1).fold(0, |sum, item| sum + item) // fold 取得1..n+1产生的每个值,把累加值和这个值传给闭包。 // 然后闭包又返回新的累加值。 }
13.1-Iterator
和 IntoIterator
特型
Rust 迭代器:是任何实现 `std::iter::Iterator 特型的值。
trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; ... // 许多默认方法 }
Item
是迭代器产生的值的类型。next
方法要么返回Some(v)
,其中v
是迭代器的下一个值;要么返回None
,表示序列终止。
IntoIterator
迭代器:实现迭代某种类型。trait IntoIterator where Self::IntoIter::Item == Self::Item { type Item; type IntoIter: Iterator; fn into_iter(self) -> Self::IntoIter; }
Item
是迭代器所产生值的类型。IntoIter
是迭代器值本身的类型。- 任何实现
IntoIterator
特型的类型,被称为可迭代类型(iterable)。
Rust 的循环可以实现迭代操作。如下所示迭代某个向量的元素:
println!("There's: "); let v = vec!["antimony", "arsenic", "aluminum", "selenium"]; for element in &v { // 迭代器 println!("{}", element); // 消费者 }
每个循环本质上只是对调用
IntoIterator
和Iterator
方法的简写:let mut iterator = (&v).into_iter(); while let Some(element) = iterator.next() { println!("{}", element); }
- 循环利用
IntoIterator::into_iter
方法将其操作数&v
转换为一个迭代器。 - 然后重复调用
Iterator::next
。 - 每次返回
Some(element)
,循环都执行其循环体。 - 如果返回的是
None
,则循环结束。
- 循环利用
迭代器产生的值叫迭代项(item)。
接收迭代器产生的迭代项的代码叫消费者(consumer)。
13.2 - 创建迭代器
13.2.1-iter
和 iter_mut
方法
大多数集合类型的
iter
和iter_mut
方法,返回该类型的迭代器,产生每个迭代项的共享或可修改引用。- 如下所示迭代器的迭代项类型是
&i32
- 每次调用
next
都会产生对下一个元素的引用,直到向量的末尾。
// 代替循环实现迭代器 let v = vec![4, 20, 12, 8, 6]; let mut iterator = v.iter(); assert_eq!(iterator.next(), Some(&4)); ...
- 如下所示迭代器的迭代项类型是
std::path::Path
的iter
方法返回的迭代器每次会产生路径的一个组件:- 这个迭代器的迭代项的类型是
&std::ffi::OsStr
; - 是操作系统调用可以接受的、借用的字符串切片。
use std::ffi::OsSter; use std::path::Path; let path = Path::new("C:/users/JimB/Downloads/Fedora.iso"); let mut iterator = path.iter(); assert_eq!(iterator.next(), Some(OsStr::new("C:"))); assert_eq!(iterator.next(), Some(OsStr::new("users"))); ...
- 这个迭代器的迭代项的类型是
13.2.2-IntoIterator
实现
如前所述,如果类型实现了
IntoIterator
,则可以调用它的into_iter
方法,实现等同循环的效果。use std::collections::BTreeSet; let mut favorites = BTreeSet::new(); favorites.insert("Lucy".to_string()); favorites.insert("Lie No. 3".to_string()); let mut it = favorites.into_iter(); assert_eq!(it.next(), Some("Lie No. 3".to_string())); assert_eq!(it.next(), Some("Lucy".to_string())); assert_eq!(it.next(), None);
大多数集合实现了多个
IntoIterator
,分别用于共享引用、可修改引用和转移。- 对于集合的共享引用:
into_iter
会返回产生迭代项共享引用的迭代器。 - 对于集合的可修改引用:
into_iter
会返回产生迭代项可修改引用的迭代器。 - 对于集合的按值转移:
into_iter
返回的迭代器会取得集合的所有权,并按值返回迭代器。此时,迭代器的所有权从结合转移到消费者,原始集合在这个过程中会被消费掉。
- 对于集合的共享引用:
for
循环会对其操作数应用IntoIterator::into_iter
,所以下述 3 个实现,可以支持迭代集合的共享引用、可修改引用,以及消费集合并取得其元素的所有权:- 每种实现,都对应上面的一种
IntoIterator
实现。
for element in &collection { ... } for element in &mut collection { ... } for element in collection { ... }
- 每种实现,都对应上面的一种
HashSet
、BTreeSet
和BinaryHeap
没有对可修改引用实现IntoIterator
。HashMap
和BTreeMap
会产生它们值的可修改引用,但只产生它们键的共享引用。切片实现了
IntoIterator
的共享引用和可修改引用。IntoIterator
的共享引用和可修改引用的实现,等价于在引用值上调用iter
或iter_mut
方法:IntoIterator
是for
循环底层的基础;- 在不使用
for
循环时,it.iter()
要比(&it).into_iter()
清晰。
在泛型代码中,
T: IntoIterator
绑定可以限制类型变量T
为可迭代的类型。T: IntoIterator<Item=U>
可以进一步要求迭代产生指定的类型U
。// 接收任何可迭代类型,将它们通过{:?}格式,将值打印出来 use std::fmt::Debug; fn dump<T, U>(t: T) where T: IntoIterator<Item=U>, U: Debug { for u in t { println!("{:?}", u); } }
不能使用
iter
和iter_mut
来实现这个泛型函数,因为它们不是任何特型的方法。
13.2.3-drain
方法
drain
方法:以一个集合的可修改引用为参数,返回一个能把每个元素所有权传给消费者的迭代器。- 只是借用对集合的引用。
- 在迭代器被清除后,它会清空集合中所有剩余的元素。
在可通过范围指定索引的类型,如
String
、向量和VecDeque
中,drain
方法接收要移除元素的范围,而不是排取(drain)整个序列:use std::iter::FromIterator; let mut outer = "Eearth".to_string(); let inner = String::from_iter(outer.drain(1..4)); assert_eq!(outer, "Eh"); assert_eq!(inner, "art");
如果确实要排取整个序列,那么可以使用全范围(
..
)作为参数。
13.2.4 - 其他迭代器源
类型或特型 | 表达式 | 说明 |
---|---|---|
std::ops::Range | 1..10 | 端点必须是可以迭代的整数类型。范围包含起始值,不包含终止值。 |
std::ops::RangeFrom | 1.. | 无限定迭代。起始值必须时整数。如果值超过类型限制,可能会诧异或溢出 |
Option<T> | Some(10).iter() | 类似长度为 0(None )或 1(Some(v) )的向量 |
Result<T, E> | Ok("blah").iter() | 类似 Option ,产生 Ok 值 |
Vec<T>, &[T] | v.windows(16) | 从左到右产生给定长度的每个连续切片。窗口重叠 |
v.chunks(16) | 从左到右产生给定长度的非重叠连续切片 | |
v.chunks_mut(1024) | 类似 chunks ,但切片是可修改的 | |
`v.split( | byte | |
v.split_mut(...) | 同上,但产生可修改切片 | |
v.rsplit(...) | 类似 split ,但从右到左产生切片 | |
v.splitn(n, ...) | 类似 split ,但最多产生 n 个切片 | |
String, &str | s.bytes() | 产生 UTF-8 形式的字节 |
s.chars() | 产生 UTF-8 表示的字符 | |
s.split_whitespace() | 以空格分割字符串,产生非空格字符的切片 | |
s.lines() | 产生字符串行的切片 | |
s.split('/') | 以给定模式分割字符串,产生匹配之间内容的切片。模式可以是字符、字符串、闭包等 | |
s.matches(char::is_numeric) | 产生匹配给定模式的切片 | |
std::collections::HashMap std::collections::BTreeMap | map.keys(), map.values() | 产生对映射键或值的共享引用 |
map.values_mut() | 产生对条目值的可修改引用 | |
std::collections::HashSet std::collections::BTreeSet | set1.union(set2) | 产生对 set1 与 set2 合集元素的共享引用 |
set1.intersection(set2) | 产生对 set1 与 set2 交集元素的共享引用 | |
std::sync::mpsc::Receiver | recv.iter() | 产生另一个线程中对应 Sender 发送的值 |
std::io::Read | stream.bytes() | 从 IO 流产生字节 |
stream.chars() | 将流作为 UTF-8 解析并产生字符 | |
std::io::BufRead | bufstream.lines() | 将流作为 UTF-8 解析并产生 String 行 |
bufstream.split(0) | 以给定字节分割流,产生该字节间的 Vec<u8> 缓冲 | |
std::fs::ReadDir | std::fs::read_dir(path) | 产生目录项 |
std::net::TcpListener | listener.incoming() | 产生到来的网络连接 |
Free functions | std::iter::empty() | 立即返回 None |
std::iter::once(5) | 产生给定的值,然后结束 | |
std::iter::repeat("#9") | 一直产生给定的值 |
详见《Rust 程序设计》(吉姆 - 布兰迪、贾森 - 奥伦多夫著,李松峰译)第十五章
原文地址
边栏推荐
- E: Unable to locate package ROS melody desktop full
- Base64和Base64URL
- Haproxy+kept cluster setup 02
- go 解析身份证
- Exe file running window embedding QT window
- [set theory] order relation (the relation between elements of partial order set | comparable | strictly less than | covering | Haas diagram)
- Gradle's method of dynamically modifying APK package name
- 数据的存储
- Conversion between golang JSON format and structure
- Thymeleaf 404 reports an error: there was unexpected error (type=not found, status=404)
猜你喜欢
【云原生】微服务之Feign的介绍与使用
Mxone Pro adaptive 2.0 film and television template watermelon video theme apple cmsv10 template
VIM learning notes from introduction to silk skating
ArrayList
UE4 source code reading_ Bone model and animation system_ Animation process
Solution détaillée de toutes les formules de fonction de transfert (fonction d'activation) du réseau neuronal MATLAB
P1596 [USACO10OCT]Lake Counting S
Dealing with duplicate data in Excel with xlwings
Xlua task list youyou
Unity learning notes
随机推荐
Base64编码简介
796 · 开锁
Easy touch plug-in
MAE
Visual Studio (VS) shortcut keys
C language - Introduction - essence Edition - take you into programming (I)
Jupyter remote server configuration and server startup
LinkList
Haproxy+kept build 01
Pit & ADB wireless debugging of vivo real machine debugging
[set theory] order relation (the relation between elements of partial order set | comparable | strictly less than | covering | Haas diagram)
Exe file running window embedding QT window
数据分析练习题
Gradle's method of dynamically modifying APK package name
Creation of osgearth earth files to the earth ------ osgearth rendering engine series (1)
Osgearth starry background
2021-10-19
二进制转十进制,十进制转二进制
Unity editor expansion - the framework and context of unity imgui
简易入手《SOM神经网络》的本质与原理