计算时似乎消耗了迭代器。如何使用相同的迭代器进行计数,然后对其进行迭代?
我试图计算文件中的行然后打印它们。我能够读取文件内容,我能够计算行数,但是我不再能够遍历这些行,就像内部游标位于迭代器的末尾一样。 / p>
reset
Iterator
没有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);
}
}
来创建新的Lines
,还是可以重置内部游标?
目前,我找到的解决方法是创建一个新的迭代器:
public class enemy : MonoBehaviour {
public Node nodeScript;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
test();
Debug.Log(nodeScript.FinalPath.Count);
}
public void test()
{
nodeScript.FinalPath.ForEach(x => Debug.Log(x));
}
}
答案 0 :(得分:6)
调用count
会消耗迭代器,因为它实际上会迭代直到完成(即next()
返回None
)。
您可以通过使用by_ref
来阻止使用迭代器,但迭代器仍然被驱动到它的完成(by_ref
实际上只返回迭代器的可变引用,而Iterator
也是为可变引用而实现:impl<'a, I> Iterator for &'a mut I
)。
如果迭代器在完成后包含您想要重用的其他状态,那么这仍然很有用,但在这种情况下不会。
你可以简单地尝试分析迭代器(如果它们没有副作用,它们通常会实现Clone
),虽然在这种情况下重新创建它同样好(大多数时候创建迭代器很便宜;真正的工作通常只有在你通过直接或间接地调用next
来驱动它时才会完成。
所以不,(在这种情况下)你无法重置它,是的,你需要创建一个新的(或在使用之前克隆它)。
答案 1 :(得分:2)
迭代器通常不能迭代两次,因为它们的迭代可能会有成本。在str::lines
的情况下,每次迭代都需要找到行的下一行,这意味着要扫描字符串,这需要一些成本。您可以说迭代器可以保存这些位置以供以后重用,但存储它们的成本会更高。
一些Iterator
的迭代成本更高,所以你真的不想做两次。
可以轻松地重新创建许多迭代器(这里第二次调用str::lines
)或clone
d。无论您重新创建迭代器的方式如何,这两个迭代器通常都是完全独立的,因此迭代意味着您将支付两次价格。
在你的特定情况下,将字符串迭代两次可能没什么问题,因为适合内存的字符串不应该太长,以至于只计算行是非常昂贵的操作。如果你认为是这种情况,那么首先对它进行基准测试,然后编写自己的算法Lines::count
可能没有尽可能多地优化,因为Lines
的主要目标是迭代行。
答案 2 :(得分:2)
其他答案已经得到很好的解释,您可以重新创建迭代器或将其克隆。
如果迭代操作过于昂贵或不可能多次执行(例如从网络套接字读取),则另一种解决方案是创建迭代器值的集合,以允许您获取长度和值。
这确实需要存储迭代器中的每个值; 没有免费的午餐!
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);
}
}