rust - 如何为迭代器写trait&impl with lifes?

标签 rust iterator traits lifetime trait-objects

我试图了解如何为自己的类型编写traitimpl,以处理一些输入数据。我从一个简单的示例开始,在该示例中,我想使用1, 2, 3, 4处理输入的trait Processor。一个实现将跳过第一个元素,并将所有其余输入加倍。因此,它应如下所示:

trait Processor {} // TBD

struct SkipOneTimesTwo;
impl Processor for SkipOneTimesTwo {} // TBD

let numbers = vec![1, 2, 3, 4];
let it = numbers.iter();
let it = Box::new(it);

let proc = SkipOneTimesTwo;
let four_to_eight = proc.process(it);
assert_eq!(Some(4), four_to_eight.next());
assert_eq!(Some(6), four_to_eight.next());
assert_eq!(Some(8), four_to_eight.next());
assert_eq!(None, four_to_eight.next());
所以我的假设是我的特征和相应的实现看起来像这样:
trait Processor {
    // Arbitrarily convert from `i32` to `u32`
    fn process(&self, it: Box<dyn Iterator<Item = i32>>) -> Box<dyn Iterator<Item = u32>>;
}

struct SkipOneTimesTwo;
impl Processor for SkipOneTimesTwo {
    fn process(&self, it: Box<dyn Iterator<Item = i32>>) -> Box<dyn Iterator<Item = u32>> {
        let p = it.skip(1).map(|i| 2 * (i as u32));
        Box::new(p)
    }
}
此代码无法按原样工作。我收到以下错误:
7 |     let four_to_eight = proc.process(it);
  |                                      ^^ expected `i32`, found reference
  |
  = note:   expected type `i32`
          found reference `&{integer}`
  = note: required for the cast to the object type `dyn Iterator<Item = i32>`
如果我的输入数据非常大,我不希望将整个数据集都保存在内存中(使用Iterator的整个要点),因此我假设使用Iterator<T>应该从原始输入源流式传输数据,直到将其输入为止。最终汇总或以其他方式处理。但是,我不知道这意味着什么,我需要在此注释的生命周期。
最终,我的Processor可能保存来自输入的一些中间数据(例如,用于运行平均值计算),因此我可能必须在结构上指定生存期。
解决了一些编译器错误,我尝试将'a'static'_生存期添加到dyn Iterator<...>中,但是我不太清楚如何传递输入迭代器并延迟修改值。
这甚至是一种合理的方法吗?我可能可以将输入的Iterator<Item = i32>存储在我的struct和impl Iterator<Item = u32> for SkipOneTimesTwo中,但是随后我可能会失去一些能够绕过Processor特性的抽象概念。

最佳答案

Rust中的所有迭代器都是惰性的。另外,您不需要使用生存期,只需使用 into_iter() 而不是 iter() 即可编译代码:

trait Processor {
    fn process(&self, it: Box<dyn Iterator<Item = i32>>) -> Box<dyn Iterator<Item = u32>>;
}

struct SkipOneTimesTwo;

impl Processor for SkipOneTimesTwo {
    fn process(&self, it: Box<dyn Iterator<Item = i32>>) -> Box<dyn Iterator<Item = u32>> {
        let p = it.skip(1).map(|i| 2 * (i as u32));
        Box::new(p)
    }
}

fn main() {
    let numbers = vec![1, 2, 3, 4];
    let it = numbers.into_iter(); // only change here
    let it = Box::new(it);
    
    let pro = SkipOneTimesTwo;
    let mut four_to_eight = pro.process(it);
    assert_eq!(Some(4), four_to_eight.next());
    assert_eq!(Some(6), four_to_eight.next());
    assert_eq!(Some(8), four_to_eight.next());
    assert_eq!(None, four_to_eight.next());
}
playground

关于rust - 如何为迭代器写trait&impl with lifes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65781788/

相关文章:

具有特征的案例类的equals/hashCode的Scala语义

rust - Option<T> 是 Drop 的记录在哪里?

c++ - 大小为 4 的迭代器无效读取

java - 为什么 Iterable 没有义务在每次调用 iterator() 方法时都返回新的迭代器?

rust - 为什么这个特性不是对象安全的?

string - 查找连续相等字符的最长子串时出现 "borrowed value does not live long enough"错误如何处理?

c++ - 如何实现构造函数,使其只接受使用 typeid 的输入迭代器?

斯卡拉 : get mixin interfaces at runtime

rust - 在字符串拆分上使用映射时无法推断类型

performance - Rust 在解析文件时比 Python 慢