本内容是对 Rust开发干货集 的学习与实践.
迭代器
1 |
|
输出:
1 | [Person { age: 18, name: "Zhangsan" }] |
下面细细分解&增补
iter() 不转移所有权
先简单解释下什么叫”转移所有权”:
在 Rust 中,”转移所有权”(Ownership Transfer)是一种核心概念,它涉及变量和数据的所有权从一个实体转移到另一个实体。这种机制帮助 Rust 在编译时期管理内存安全,避免悬挂指针和内存泄漏等问题。
例如:
1 | fn main() { |
当 s1 被赋值给 s2 时,s1 的所有权被转移给了 s2。这意味着 s1 不再有效,因此接下来如果使用 s1 将导致编译错误。
iter() 在 Rust 中用于创建集合的迭代器,比如在数组或向量上。iter() 不会转移集合的所有权。相反,它创建一个迭代器,该迭代器借用集合的内容:
1 | fn main() { |
上例中,v.iter() 创建了一个迭代器,但 v 的所有权没有改变。因此,在迭代之后,仍然可以使用 v。
这说明iter() 不转移所有权(因为所有权转移意味着原始变量不再有效)
另外几种创建迭代器的方法: iter_mut() 和 into_iter()
iter_mut()
iter_mut() 方法用于创建一个可变借用(mutable borrow)的迭代器。其允许在迭代过程中修改集合中的元素。
(所有权并没有发生转移)
如下:
1 | fn main() { |
v.iter_mut() 创建了一个可变迭代器,允许修改向量 v 中的每个元素
into_iter()
into_iter() 方法用于创建一个取得所有权(ownership)的迭代器---这意味着迭代器会消耗(consume)集合,并拥有其元素的所有权。这通常用于在迭代时转移集合中元素的所有权。
如下:
1 | fn main() { |
v.into_iter() 创建了一个获取 v 所有权的迭代器。迭代后,v 不再有效,因为它的所有权已经被迭代器 into_iter() 消耗。
into_iter() 会转移所有权。它创建一个获取集合所有权的迭代器,允许在迭代时转移集合中元素的所有权。一旦使用了 into_iter(),原始集合将不再有效,因为它的所有权已经被迭代器取得。
即
iter_mut()用于需要修改集合中元素的场景,但并不转移所有权; 而into_iter()用于需要转移元素所有权的场景。
iter() 的 cloned()方法
iter() 方法用于创建一个不可变引用的迭代器,而 cloned() 是这类迭代器的一个方法。cloned() 的作用是将迭代器中的每个元素通过调用其 clone 方法来创建一个新的实例。这通常用于当拥有一个包含引用的迭代器,但需要迭代器中的值的拷贝时。
cloned() 的作用:
创建元素的拷贝:
cloned()方法适用于迭代器的元素实现了Clonetrait。它会为每个元素创建一个新的实例,这是通过调用每个元素的clone方法实现的。不转移所有权:由于
cloned()仅仅是创建元素的副本,它不会改变原始数据的所有权。
如下例: 假设有一个Vec,其中包含一些数字的引用,现在想要迭代这些数字的拷贝而不是引用本身:
1 | use std::any::type_name; |
输出为:
1 | 1 |
在上例中,使用 cloned() 方法,可以将这些引用转换为实际的数字拷贝,从而创建一个新的 Vec<i32>。这样,nums_cloned 就包含了 nums 中每个元素的拷贝,而不是引用。
即
cloned()在 Rust 中用于从迭代器中创建元素的拷贝,特别是当有一个包含引用的迭代器 并希望获得实际值的拷贝时。它是处理引用集合时常用的便捷方法。
iter_mut() 有没有 cloned()方法?
iter_mut() 方法返回的迭代器是一个可变引用的迭代器。由于 cloned() 方法是用于拷贝迭代器中的值,它通常与不可变引用的迭代器(如由 iter() 返回的迭代器)一起使用。cloned() 方法适用于那些实现了 Clone trait 的元素,它会创建每个元素的拷贝。
对于 iter_mut() 返回的迭代器,由于它提供的是对元素的可变引用(&mut T),使用 cloned() 方法是不适当的,也不符合 Rust 的安全性原则。可变引用的目的是允许修改集合中的元素,而不是创建它们的拷贝。如果需要修改元素并且需要它们的拷贝,应该首先通过其他方式创建拷贝,然后对这些拷贝进行修改。
因此,在实际的 Rust 编程实践中,iter_mut() 迭代器上不会使用 cloned() 方法。如果需要元素的拷贝,应该使用 iter() 方法来创建一个不可变引用的迭代器,然后在该迭代器上使用 cloned()
map/fold(reduce)/filter的作用
更多可参考 初探函数式编程—以Map/Reduce/Filter为例
map用于对迭代器中的 每个元素 应用某个函数/执行某项(会发生修改的)操作,并返回一个新的迭代器。
例如:
1 | let numbers = [1, 2, 3, 4, 5]; |
1 | fn main() { |
输出:
1 | 2 |
fold用于将迭代器中的元素进行累积计算,其基本语法是:
1 | iter.fold(init, |acc, x| { |
fold需要两个参数:
- init:初始累积值
- 闭包:接收当前累积值acc和元素x,返回更新后的acc
例如:
1 | fn main() { |
这里fold的init值为0,闭包中每次将acc和x相加,返回更新后的acc,最终将数组所有元素求和。
另一个例子,连接字符串:
1 | fn main() { |
fold可以将迭代中的元素进行任意累积计算,常见用法包括求和、乘积、字符串连接等。fold()消费器可以实现reduce逻辑
filter用于过滤迭代器中的元素,只保留满足条件的元素。
例如:
1 | let numbers = [1, 2, 3, 4, 5]; |
1 | fn main() { |
输出:
1 | 2 |
filter_map() 可以同时完成转换和过滤
filter_map() 方法结合了过滤(filter)和映射(map)功能。
这个方法接收一个闭包,该闭包作用于迭代器的每个元素,并返回 Option<T> 类型。filter_map() 然后自动过滤掉所有返回 None 的元素,并将所有 Some 包裹的值提取出来,形成一个新的迭代器。
过滤和转换:
filter_map()允许同时对迭代器的元素进行过滤和转换。如果闭包返回Some(value),则value被包含在新迭代器中;如果闭包返回None,则该元素被过滤掉。可选的转换:与
map()相比,filter_map()允许根据元素的值选择性地包含或排除元素,而不是简单地映射每个元素到另一个值。
举个例子, 假设有一个字符串类型的向量,想将其中的每个字符串转换为整数。但不是所有的字符串都可以转换为整数(例如,某些字符串可能包含非数字字符,如”1ab”)。
在这种情况下,就可以使用 filter_map() 来尝试解析每个字符串,并仅保留那些成功解析为整数的元素:
1 | fn main() { |
在上例中,filter_map() 尝试将每个字符串转换为 i32。如果 parse 方法成功(即返回 Ok(value)),filter_map() 将 Some(value) 包装的 value 加入到新的迭代器中。如果 parse 失败(即返回 Err),filter_map() 则通过 ok() 方法将 Err 转换为 None,从而过滤掉这些元素。
通过这种方式,filter_map() 使得同时进行过滤和映射变得简单而高效。
另外一些消费器
上面介绍的 map、fold 和 filter ,都属于消费器, 消费器在Rust中是指能够消费迭代器的类型
另外还有一些常用的消费器,包括:
- collect():将迭代器收集到集合类型如Vec/String中
collect()消费器可以实现集合类型转化
1 | fn main() { |
- sum():计算迭代器元素的和。
1 | fn main() { |
- min()/max():找到迭代器最小/最大元素。
1 | fn main() { |
- count():统计迭代器元素数量。
1 | fn main() { |
- any()/all():是否存在(某个元素)/所有元素满足条件。
any()消费器可以查找是否存在满⾜条件的元素,迭代器是惰性的,any消费器可能不需要遍历Iterator
1 | fn main() { |
1 | fn main() { |
- find():找到第一个满足条件的元素并输出,否则返回None
1 | fn main() { |
这些消费器都会完全消费迭代器,将其结果返回。它们常用于迭代器计算的最后阶段,将迭代结果转化为具体值。
https://zhuanlan.zhihu.com/p/346583098
https://aandds.com/blog/rust-iterator.html
https://blog.csdn.net/feiyanaffection/article/details/125574919
https://blog.csdn.net/qq_21484461/article/details/131649337
https://course.rs/advance/functional-programing/iterator.html
https://kaisery.github.io/trpl-zh-cn/ch13-02-iterators.html
原文链接: https://dashen.tech/2023/12/29/Rust开发⼲货集/
版权声明: 转载请注明出处.