在 Rust 中组合同一范围内的多个迭代器

问题描述 投票:0回答:1

我试图理解同一跨度上的 Rust 迭代器如何(以及为什么)无法组合(容易?)。

这是导致问题的代码片段:

let fold_size = 1;
let field = "12345678\n12345678";

let fold1 = field.lines().take(fold_size);
let fold2 = field.lines().skip(fold_size).take(fold_size).rev();

let folds = fold1.zip(fold2);

if folds.all(|(a, b)| a == b) {
    return fold + 1
}

本质上,这段代码试图迭代同一字符串的不同行几次并比较它们。至少那是我的意图。

但是,当我尝试编译此代码时,编译器会抛出多个我无法理解的错误:

error[E0277]: the trait bound `std::str::Lines<'_>: ExactSizeIterator` is not satisfied

let fold2 = field.lines().skip(fold_size).take(fold_size).rev();
                                                          ^^^ the trait `ExactSizeIterator` is not implemented for `std::str::Lines<'_>`

据我所知,这是 Rust 告诉我行上的迭代器不满足某些要求(我不太明白 -

take(n)
对我来说看起来像一个“精确大小的迭代器”)。

这很奇怪,但我可以通过使用次优黑客来解决这个问题 - 将迭代器具体化为向量:

let fold2 = field.lines().skip(fold_size).take(fold_size).collect::<Vec<_>>().iter().rev();

另一个错误(如果上面的 hack 没有实现)与

zip
操作有关:

error[E0277]: the trait bound `std::str::Lines<'_>: ExactSizeIterator` is not satisfied

let folds = fold1.zip(fold2); // the trait bound `std::str::Lines<'_>: std::iter::ExactSizeIterator` is not satisfied
                  ^^^ the trait `ExactSizeIterator` is not implemented for `std::str::Lines<'_>`

这似乎与

rev
操作有同样的问题。

all
操作发生下一个错误:

error[E0599]: the method `all` exists for struct `Zip<Take<Lines<'_>>, Rev<Take<Skip<Lines<'_>>>>>`, but its trait bounds were not satisfied

if folds.all(|(a, b)| a == b) {
         ^^^ method cannot be called on `Zip<Take<Lines<'_>>, Rev<Take<Skip<Lines<'_>>>>>` due to unsatisfied trait bounds

     |
15   | pub struct Rev<T> {
     | ----------------- doesn't satisfy `_: Iterator`
     |
13   | pub struct Zip<A, B> {
     | -------------------- doesn't satisfy `_: Iterator`
     |

这对我来说没有任何意义。

除此之外,

rust-analyzer
还抛出了一个超级可疑的警告:

if folds.all(|(a, b)| a == b) {
   ^^^^^
cannot mutate immutable variable `folds`rust-analyzer (E0384)
---
let folds: Zip<Take<Lines<'_>>, <Rev<Take<Skip<Lines<'_>>>> as IntoIterator>::IntoIter>

这对我来说没有任何意义 - 看起来我并没有(明确地)改变迭代器。我可以理解该操作如何在范围内进行迭代,但这不应该是一个新的迭代器实例吗?

根据文档,所有上述操作都应该返回一个迭代器(

Lines::rev
Lines::take
Lines::zip
)?

我的理解是这些迭代器应该是“零成本抽象”,仅描述迭代同一集合中的一系列值的方式。

但显然迭代器的实现或使用这些迭代器的代码中缺少一些东西 - 我只是无法理解这里到底出了什么问题。或者我可能误解了 Rust 迭代器的核心概念。

string rust iterator
1个回答
1
投票

Lines
中的元素数量取决于输入,因此它无法实现
ExactSizeIterator
,进一步
take(n)
返回一个最多
n
元素的迭代器,如果包含的迭代器更短,那么是结果
Take
,所以一般来说,它也不能实现
ExactSizeIterator
。问题是
Take
仅实现
DoubleEndededIterator
当且仅当所包含的迭代器实现
ExactSizeIterator
(不仅仅是
DoubleEndedIterator
),因为它是如何实现的。

您可能应该将线路收集到临时的

Vec
中。

© www.soinside.com 2019 - 2024. All rights reserved.