如何使用相同的迭代器两次,一次用于计数,一次用于迭代?

时间:2017-12-30 19:21:19

标签: iterator rust reset

计算时似乎消耗了迭代器。如何使用相同的迭代器进行计数,然后对其进行迭代?

我试图计算文件中的行然后打印它们。我能够读取文件内容,我能够计算行数,但是我不再能够遍历这些行,就像内部游标位于迭代器的末尾一样。 / 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));

    }
}

3 个答案:

答案 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);
    }
}
相关问题