从一个向量多次使用迭代器作为函数的参数
Using an iterator as an argument to a function multiple times from one vector
我正在尝试编写一些 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));
}
我尝试了几种不同的变体,但 none 似乎有效。在这种特殊情况下,我得到
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());
您声明您想要 returns usize
项的迭代器,但 small_data.iter()
是 returns 引用 usize
项的迭代器(&usize
)。这就是您收到错误 "expected reference, found usize" 的原因。 usize
是一种可克隆的小型类型,因此您可以简单地使用 .cloned()
迭代器适配器来提供实际上 returns 一个 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 代码来解码来自 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));
}
我尝试了几种不同的变体,但 none 似乎有效。在这种特殊情况下,我得到
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());
您声明您想要 returns usize
项的迭代器,但 small_data.iter()
是 returns 引用 usize
项的迭代器(&usize
)。这就是您收到错误 "expected reference, found usize" 的原因。 usize
是一种可克隆的小型类型,因此您可以简单地使用 .cloned()
迭代器适配器来提供实际上 returns 一个 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));
}