Rust 迭代器
迭代器
迭代器是惰性的,调用方法使用迭代器之前,不会有任何的效果。
每个迭代器都实现了iterator trait,这个 trait 定义在标准库里。
trait Iterator {
type Item;
// type Item和Self::Item这种用法叫做定义trait的关联类型。这里只定义了这个函数,并没有实现,如果使用自定义迭代器的话,就要在这里的重写next方法。
fn next(&mut self) -> Option<Self::Item>;
}
fn iter_check() {
let v1 = vec![1, 2, 3];
let mut v1_iter = v1.iter();
if let Some(v) = v1_iter.next() {
println!("{}", v);
} else {
println!("end")
}
}
next 方法是被要求实现的唯一的一个方法,next一次返回一个元素,当迭代器结束的时候返回None。
迭代可变引用
fn iter_check_mut() {
// 通过迭代的方法修改列表
let mut v2 = vec![1, 2, 3];
let mut v2_iter = v2.iter_mut();
if let Some(v) = v2_iter.next() {
*v = 3
}
println!("{:?}", v2_iter)
}
自定义迭代器
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
Counter {count: 0, }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count < 6 {
Some(self.count)
} else {
None
}
}
}
fn main() {
let mut counter = Counter::new();
for i in (0..6) {
if let Some(v) = counter.next() {
println!("{} {}", i, v);
} else {
println!("{}", i);
break;
}
}
println!("Hello, world!");
}
什么是关联类型?
关联类型是trait定义的类型占位符,定义的时候,并不知道它的具体类型是什么(有点类似泛型)。在impl这个trait的时候,才为这个关联类型赋予确定的类型。也就是说
在实现的时候,才知道它的具体类型是什么。
trait和泛型参数的区别
trait和泛型参数虽然可以实现相同的工作,但是其中有区别。
- 如果trait包含泛型参数,那么可以对同一个目标多次impl此trait,每次提供不同的泛型参数。而关联类型方式只允许对目标类型实现一次。
- 如果trait包含泛型参数,那么在具体调用的时候就需要标注以明确使用的是哪一个具体的实现。关联类型则不需要标注,(因为不存在模棱两可的情况)。
其实泛型和关联类型并没有必然的关系,本身都是不同维度的东西。
关于迭代器中的scan函数的一点理解
scan和fold很类似,但是它允许你直接修改累计值,并且允许你选择什么时候停止迭代,取决于你传入的闭包何时返回None。比如我不仅要求数组的和,还要获取每次累加的结果,就可以这么写。
fn main() {
let vec = vec![1, 2, 3, 4, 5];
for step in vec.iter().scan(0, |acc, x| {
*acc+= *x;
Some(*acc)
}) {
eprint!("{} ", step);
}//打印1 3 6 10 15
}
这里的scan每次循环都返回一个Option类型的枚举,Some是作为返回值。当scan里循环完之后,就返回None,循环结束