我有这个玩具示例,但这是我想要完成的:
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 i64
或 expected i64, found &i64
)。我尝试了其他方法来声明所涉及的类型,但我基本上只是盲目地在某些地方添加 &
和 *
而没有取得任何进展。
我在这里错过了什么?我需要更改什么才能进行编译?
编辑
这里有一个更具体的例子 - 我需要 iter
为 mut
这样我就可以在实际调用 .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
存在以复制迭代值。在这种情况下,它转换 &i64
到i64
本质上是取消引用该值:
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/