计数的时候好像消耗了一个迭代器。如何使用同一个迭代器进行计数然后对其进行迭代?
我正在尝试计算文件中的行数,然后打印它们。我能够读取文件内容,我能够计算行数,但随后我无法再迭代这些行,就好像内部光标位于迭代器的末尾一样。
use std::fs::File;
use std::io::prelude::*;
fn main() {
let log_file_name = "/home/myuser/test.log";
let mut log_file = File::open(log_file_name).unwrap();
let mut log_content: String = String::from("");
//Reads the log file.
log_file.read_to_string(&mut log_content).unwrap();
//Gets all the lines in a Lines struct.
let mut lines = log_content.lines();
//Uses by_ref() in order to not take ownership
let count = lines.by_ref().count();
println!("{} lines", count); //Prints the count
//Doesn't enter in the loop
for value in lines {
println!("{}", value);
}
}
Iterator
没有 reset
方法,但似乎内部游标在计数后位于迭代器的末尾。是否必须再次调用 Lines
来创建新的
log_content.lines()
或者我可以重置内部光标吗?
目前,我找到的解决方法是创建一个新的迭代器:
use std::fs::File;
use std::io::prelude::*;
fn main() {
let log_file_name = "/home/myuser/test.log";
let mut log_file = File::open(log_file_name).unwrap();
let mut log_content: String = String::from("");
//Reads the log file.
log_file.read_to_string(&mut log_content).unwrap();
//Counts all and consume the iterator
let count = log_content.lines().count();
println!("{} lines", count);
//Creates a pretty new iterator
let lines = log_content.lines();
for value in lines {
println!("{}", value);
}
}
count()
会消耗迭代器,因为它实际上会迭代直到完成(即 next()
返回 None
)。
by_ref()
来防止消耗迭代器,但迭代器仍然会被驱动完成(by_ref()
实际上只是返回对迭代器的可变引用,并且 Iterator
也实现了可变引用:impl<'a, I> Iterator for &'a mut I
)。
如果迭代器包含完成后您想要重用的其他状态,这仍然很有用,但在这种情况下则不然。
Clone
),尽管在这种情况下重新创建它也同样好(大多数时候创建迭代器很便宜;真正的通常只有当您通过直接或间接调用 next
来驱动它时,工作才会完成。
所以不,(在这种情况下)您无法重置它,是的,您需要创建一个新的(或在使用它之前克隆它)。
其他答案已经很好地解释了,您可以重新创建迭代器或克隆它。
如果迭代行为过于昂贵或者不可能多次执行(例如从网络套接字读取),则另一种解决方案是创建迭代器值的集合,以便您获取长度和值。
这确实需要存储迭代器中的每个值; 天下没有免费的午餐!
use std::fs;
fn main() {
let log_content = fs::read_to_string("/home/myuser/test.log").unwrap();
let lines: Vec<_> = log_content.lines().collect();
println!("{} lines", lines.len());
for value in lines {
println!("{}", value);
}
}
迭代器通常不能迭代两次,因为迭代可能会产生成本。在
str::lines
的情况下,每次迭代都需要找到下一个行尾,这意味着扫描字符串,这会产生一些成本。 您可能会说迭代器可以保存这些位置以供以后重用,但存储它们的成本会更大。
有些
Iterator
的迭代成本甚至更高,所以你真的不想重复两次。
许多迭代器可以轻松地重新创建(此处再次调用
str::lines
)或被 clone
d。无论您以哪种方式重新创建迭代器,这两个迭代器通常都是完全独立的,因此迭代意味着您将付出两次代价。
在您的具体情况下,只需将字符串迭代两次可能就可以了,因为适合内存的字符串不应该太长,以至于仅仅计算行数将是一项非常昂贵的操作。如果您认为是这种情况,请首先对其进行基准测试,然后编写自己的算法,因为
Lines::count
可能没有得到尽可能多的优化,因为 Lines
的主要目标是迭代行。