Ant*_*nyB 3 iterator reset rust
似乎在计数时消耗了迭代器.我如何使用相同的迭代器进行计数然后迭代它?
我正在尝试计算文件中的行,然后打印它们.我能够读取文件内容,我能够计算行数,但是我不再能够遍历这些行,就像内部游标位于迭代器的末尾一样.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
调用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);
}
}
Run Code Online (Sandbox Code Playgroud)
迭代器通常不能迭代两次,因为迭代可能会产生成本。在 的情况下str::lines,每次迭代都需要找到下一个行尾,这意味着扫描字符串,这会产生一些成本。您可能会说迭代器可以保存这些位置以供以后重用,但存储它们的成本会更大。
有些Iterator迭代的成本甚至更高,所以你真的不想重复两次。
许多迭代器可以轻松地重新创建(此处称为str::lines第二次调用)或被clone删除。无论您以哪种方式重新创建迭代器,这两个迭代器通常都是完全独立的,因此迭代意味着您将付出两次代价。
在您的特定情况下,只需将字符串迭代两次就可以了,因为适合内存的字符串不应该太长,以至于仅仅计算行数将是一项非常昂贵的操作。如果您认为是这种情况,请首先对其进行基准测试,其次编写您自己的算法,因为它的主要目标是迭代行,Lines::count因此可能没有尽可能优化。Lines
| 归档时间: |
|
| 查看次数: |
1714 次 |
| 最近记录: |