rust - 从切片生成的迭代器使用什么类型签名?

标签 rust

我有这个玩具示例,但这是我想要完成的:

fn lazy_vec() {
    let vec: Vec<i64> = vec![1, 2, 3, 4, 5];
    let mut iter: Box<Iterator<Item = i64>> = Box::new(vec.into_iter());
    iter = Box::new(iter.map(|x| x + 1));
    // potentially do additional similar transformations to iter
    println!("{:?}", iter.collect::<Vec<_>>());
}

这(如果我没记错的话)是一个惰性迭代器模式,实际的 map 操作直到调用 .collect() 才会发生。我想对切片做同样的事情:

fn lazy_slice() {
    let vec: Vec<i64> = vec![1, 2, 3, 4, 5];
    let slice: &[i64] = &vec[..3];
    let mut iter: Box<Iterator<Item = i64>> = Box::new(slice.into_iter());
    iter = Box::new(iter.map(|x| x + 1));
    // potentially do additional similar transformations to iter
    println!("{:?}", iter.collect::<Vec<_>>());
}

这会导致类型不匹配:

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

我不知道我需要做什么来解决这个错误。第二个 note 让我觉得我需要:

iter = Box::new(iter.map(|x| x + 1) as Iterator<Item = i64>);

iter = Box::new(iter.map(|x| x + 1)) as Box<Iterator<Item = i64>>;

这些失败并出现其他错误,具体取决于确切的语法(例如 expected reference, found i64expected i64, found &i64)。我尝试了其他方法来声明所涉及的类型,但我基本上只是盲目地在某些地方添加 &* 而没有取得任何进展。

我在这里错过了什么?我需要更改什么才能进行编译?


编辑

这里有一个更具体的例子 - 我需要 itermut 这样我就可以在实际调用 .collect( )。我的印象是这是一种有点常见的模式,如果不正确,我们深表歉意。

fn lazy_vec(n: i64) {
    let vec: Vec<i64> = vec![1, 2, 3, 4, 5];
    let mut iter: Box<Iterator<Item = i64>> = Box::new(vec.into_iter());
    for _ in 0..n {
        iter = Box::new(iter.map(|x| x + 1));
    }
    println!("{:?}", iter.collect::<Vec<_>>());
}

我知道我可以用更简单的方式重写这个特定任务(例如,将 n 添加到每个元素的单个 map)——这是一个过于简化的 MCVE我遇到的问题。我的问题是这适用于 lazy_vec,但我不确定如何对切片执行相同的操作。


编辑2

我刚刚开始学习 Rust,一些术语和概念对我来说是新的。为了比较,这是我设想在 Python 中做的事情。我的意图是对切片执行与我目前可以对向量执行的操作相同的操作。

#!/usr/bin/env python3

import itertools

ls = [i for i in range(10)]

def lazy_work(input):
  for i in range(10):
    input = (i + 1 for i in input)
  # at this point no actual work has been done
  return input

print("From list: %s" % list(lazy_work(ls)))
print("From slice: %s" % list(lazy_work(itertools.islice(ls, 5))))

显然在 Python 中输入没有问题,但希望这能更清楚地表明我的意图?

最佳答案

What is the difference between iter and into_iter? 中所述,这些方法创建迭代器,当在 Vec 上调用时会产生不同的类型与切片相比。

[T]::iter [T]::into_iter 都返回一个迭代器 which yields values of type &T .这意味着返回值没有实现 Iterator<Item = i64>而是Iterator<Item = &i64> ,如错误消息所述。

但是,您随后的 map语句更改迭代器项的类型为 i64 ,这意味着迭代器的类型也需要更改。打个比方,您基本上是这样尝试的:

let mut a: &i64 = &42;
a = 99;

Iterator::cloned 存在以复制迭代值。在这种情况下,它转换 &i64i64本质上是取消引用该值:

fn lazy_slice(n: i64) {
    let array = [1i64, 2, 3, 4, 5];
    let mut iter: Box<Iterator<Item = i64>> = Box::new(array.iter().cloned());
    for _ in 0..n {
        iter = Box::new(iter.map(|x| x + 1));
    }
    println!("{:?}", iter.collect::<Vec<_>>());
}

关于rust - 从切片生成的迭代器使用什么类型签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47356509/

相关文章:

c++ - 如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

pointers - 如何从 Box<Trait> 获取指向虚拟表的指针?

rust - 如果main返回Err,Rust程序返回什么退出代码

generics - 是否可以通过 Rust 中的模式匹配来解压通用元组?

rust - 为什么 Vec 不实现 Iterator 特性?

rust - 为什么测试失败并显示消息 "panicked at Box<Any>"?

rust - 如何转换原始类型?

rust - 迭代递归结构时无法获取可变引用 : cannot borrow as mutable more than once at a time

rust - 为什么这个变量的生命周期不够长?

datetime - 为什么在使用请求时解析我的日期成功,但在使用 reqwests 时失败?