rust - 使用迭代器作为来自一个向量的函数的参数多次

标签 rust iterator ownership

我正在尝试编写一些 Rust 代码来解码来自 SDR 接收器的 GPS 数据。我从文件中读取样本并将二进制数据转换为一系列复数,这是一个耗时的过程。然而,有时我想流式传输样本而不将它们保留在内存中(例如,一个非常大的文件仅以一种方式处理或直接从接收器获取样本),而有时我想将整个数据集保留在内存中(例如,一个非常大的文件仅以一种方式处理)。一个小文件以多种不同的方式处理),以避免重复解析二进制文件的工作。

因此,我想用迭代器编写尽可能通用的函数或结构,但我知道它们的大小没有限制,所以我需要将它们放在 Box 中。我本来希望这样的事情能够发挥作用。

这是我能想到的最简单的例子来演示相同的基本问题。

fn sum_squares_plus(iter: Box<Iterator<Item = usize>>, x: usize) -> usize {
    let mut ans: usize = 0;
    for i in iter {
        ans += i * i;
    }
    ans + x
}

fn main() {
    // Pretend this is an expensive operation that I don't want to repeat five times
    let small_data: Vec<usize> = (0..10).collect();

    for x in 0..5 {
        // Want to iterate over immutable references to the elements of small_data
        let iterbox: Box<Iterator<Item = usize>> = Box::new(small_data.iter());
        println!("{}: {}", x, sum_squares_plus(iterbox, x));
    }

    // 0..100 is more than 0..10 and I'm only using it once,
    // so I want to 'stream' it instead of storing it all in memory
    let x = 55;
    println!("{}: {}", x, sum_squares_plus(Box::new(0..100), x));
}

我尝试了几种不同的变体,但似乎都不起作用。在这种特殊情况下,我得到

error[E0271]: type mismatch resolving `<std::slice::Iter<'_, usize> as std::iter::Iterator>::Item == usize`
  --> src/main.rs:15:52
   |
15 |         let iterbox: Box<Iterator<Item = usize>> = Box::new(small_data.iter());
   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found usize
   |
   = note: expected type `&usize`
              found type `usize`
   = note: required for the cast to the object type `dyn std::iter::Iterator<Item = usize>`

我并不担心并发性,我很乐意让它在单个线程上按顺序工作,但并发解决方案将是一个很好的奖励。

最佳答案

您遇到的当前错误如下:

let iterbox:Box<Iterator<Item = usize>> = Box::new(small_data.iter());

您声明您想要一个返回 usize 的迭代器项目,但是 small_data.iter()是一个迭代器,返回对 usize 的引用项目(&usize)。这就是为什么您会收到错误“预期引用,发现使用”。 usize是一种可克隆的小型类型,因此您可以简单地使用 .cloned()迭代器适配器提供实际返回 usize 的迭代器。

let iterbox: Box<Iterator<Item = usize>> = Box::new(small_data.iter().cloned());

一旦克服了这个障碍,下一个问题是迭代器返回 small_data包含对 small_data 的引用。自 sum_squares_plus被定义为接受 Box<Iterator<Item = usize>> ,该签名暗示 Iterator盒子内的特征对象有一个 'static生命周期。您提供的迭代器不会,因为它借用了 small_data 。要解决此问题,您需要调整 sum_squares_plus定义为

fn sum_squares_plus<'a>(iter: Box<Iterator<Item = usize> + 'a>, x: usize) -> usize

注意 'a生命周期注释。然后应该编译代码,但除非存在除此处明确定义之外的一些约束,否则更惯用和更有效的方法是避免使用特征对象和关联的分配。下面的代码应该使用静态调度来工作,而不需要任何特征对象。

fn sum_squares_plus<I: Iterator<Item = usize>>(iter: I, x: usize) -> usize {
    let mut ans: usize = 0;
    for i in iter {
        ans += i * i;
    }
    ans + x
}

fn main() {
    // Pretend this is an expensive operation that I don't want to repeat five times
    let small_data: Vec<usize> = (0..10).collect();

    for x in 0..5 {
        println!("{}: {}", x, sum_squares_plus(small_data.iter().cloned(), x));
    }

    // 0..100 is more than 0..10 and I'm only using it once,
    // so I want to 'stream' it instead of storing it all in memory
    let x = 55;
    println!("{}: {}", x, sum_squares_plus(Box::new(0..100), x));
}

关于rust - 使用迭代器作为来自一个向量的函数的参数多次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56467085/

相关文章:

rust - 如何在遍历 Vector 时从字符串复制字符串?

multithreading - 生成和管理后台线程的惯用 Clojure 方式

rust - 为什么 Rust 允许将向量中的整数值分配给另一个变量?

rust - diesel 应该使用同步 actor、actix_web::web::block 还是 futures-cpupool 来运行?

rust - 同时切片和 iter()

rust - Rust 中的 Rc::clone(&rc) 和 rc.clone() 之间有什么区别吗?是否有基于此的编译优化?

java - 什么是无限迭代器?为什么要使用它?

java - 迭代列表映射字符串对象和编辑键时并发修改异常

php - 关联数组的下一个迭代器方法

Linux:在挂载 'external' 分区时模拟/屏蔽用户所有权?