我试图理解同一跨度上的 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 迭代器的核心概念。
Lines
中的元素数量取决于输入,因此它无法实现ExactSizeIterator
,进一步take(n)
返回一个最多n
元素的迭代器,如果包含的迭代器更短,那么是结果 Take
,所以一般来说,它也不能实现ExactSizeIterator
。问题是 Take
仅实现 DoubleEndededIterator
当且仅当所包含的迭代器实现 ExactSizeIterator
(不仅仅是 DoubleEndedIterator
),因为它是如何实现的。
您可能应该将线路收集到临时的
Vec
中。