![](/img/trans.png)
[英]What is the issue with passing an (iterator) value into a closure (expected type parameter `I`, found struct `std::slice::Iter`)?
[英]Expected std::iter::Iterator, but std::iter::Iterator found
我试图表达以下内容:
给定一个矩阵和两个索引增量,返回矩阵中的所有数字四元组:沿行、或沿列或沿某些对角线的数字四元组。
use std::iter::Iterator;
use std::iter::Peekable;
use std::ops::Range;
struct Quads<'a> {
mx: &'a Vec<Vec<u32>>,
xs: &'a mut Peekable<Range<i32>>,
ys: &'a mut Peekable<Range<i32>>,
dx: i32,
dy: i32,
}
impl<'a> Quads<'a> {
fn new(mx: &'a Vec<Vec<u32>>, dx: i32, dy: i32) -> Quads<'a> {
let ys = (if dy < 0 { -3 * dy } else { 0 })..(mx.len() as i32 - if dy > 0 { 4 * dy } else { 0 });
let xs = 0..0;
Quads{
mx: mx,
xs: &mut xs.peekable(),
ys: &mut ys.peekable(),
dx: dx,
dy: dy,
}
}
}
impl<'a> Iterator for Quads<'a> {
type Item = &'a mut dyn Iterator<Item = u32>;
fn next(&mut self) -> Option<Self::Item> {
while self.xs.peek() == None && self.ys.peek() != None {
self.xs = &mut ((if self.dx < 0 { -3 * self.dx } else { 0 })..
(self.mx[0].len() as i32 - if self.dx > 0 { 4 * self.dx } else { 0 }))
.peekable();
self.ys.next();
}
let y = self.ys.peek();
if y == None {
return None;
}
let y = *y.unwrap();
let x = self.xs.next().unwrap();
Some(&mut ((x..).step_by(self.dx as usize)
.zip((y..).step_by(self.dy as usize))
.take(4)
.map(|(x,y)| self.mx[y as usize][x as usize])))
}
}
这会产生令人困惑的错误消息:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:52:27
|
52 | .map(|(x,y)| self.mx[y as usize][x as usize])))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 33:4...
--> src/main.rs:33:4
|
33 | / fn next(&mut self) -> Option<Self::Item> {
34 | | while self.xs.peek() == None && self.ys.peek() != None {
35 | | self.xs = &mut ((if self.dx < 0 { -3 * self.dx } else { 0 })..
36 | | (self.mx[0].len() as i32 - if self.dx > 0 { 4 * self.dx } else { 0 }))
... |
52 | | .map(|(x,y)| self.mx[y as usize][x as usize])))
53 | | }
| |____^
= note: ...so that the types are compatible:
expected &&mut Quads<'a>
found &&mut Quads<'a>
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 30:6...
--> src/main.rs:30:6
|
30 | impl<'a> Iterator for Quads<'a> {
| ^^
= note: ...so that the types are compatible:
expected std::iter::Iterator
found std::iter::Iterator
这似乎表明它找到了它正在寻找的相同的东西。 那么怎么了?
有可能的使用
看https://projecteuler.net/problem=11
当然,这个问题可以用更直接的方式解决,但我正在学习如何在 Rust 中表达复杂的东西。 所以在这里我试图表达一个Quad
,它是一个Iterator
,可以从欧拉问题中提取数字的四元组,其中每个四元组本身就是一个Iterator
。
Quad
所有内容都代表Iterator
的状态。 xs
和ys
表示“当前单元格”坐标的迭代器,从中开始下一个四元组。 next
然后尝试查看是否到达行尾,并通过将xs
重新初始化为新的Iterator
来前进到下一行。 当ys
超出最后一行时,我们已经提取了所有四元组。
然后是这样的:
for q in Quad::new(mx, 1, 0) { ... process all quadruples along the rows }
for q in Quad::new(mx, 0, 1) { ... process all quadruples along the columns }
for q in Quad::new(mx, 1, 1) { ... process all quadruples along one diagonal }
for q in Quad::new(mx, 1, -1) { ... process all quadruples along the other diagonal }
我想我已经掌握了这个想法,但我不知道编译器不喜欢它的什么,以及如何继续前进。
好的,所以我想通了。 rustc
产生如此令人困惑的错误消息真的没有帮助 - 显然,它找到了它要找的东西,但仍然不满意。
发布的代码有几个问题。 我最初的假设是,通过将引用标记为可变的,我可以告诉编译器,从今以后,任何接收引用的人都对其负责,包括内存管理。 尽管在某些情况下它可能是正确的(我不确定;这仍有待弄清楚),但它肯定不适用于struct
字段( Quad
的xs
)和返回值。 在这种情况下,我们可以在xs
和ys
的声明中去掉&mut
:
struct Quads<'a> {
mx: &'a Vec<Vec<u32>>,
xs: Peekable<Range<i32>>,
ys: Peekable<Range<i32>>,
dx: i32,
dy: i32,
}
另一个问题是,如果它不是引用,您如何限制值的生命周期。 (例如,在这种情况下, next
返回的Iterator
仅在mx
)
另一个问题是表达式问题:你如何让next
返回一个Iterator
(我不想泄露什么样的Iterator
),这样编译器就会高兴。 (例如只是dyn Iterator
不会做 - “编译时不知道大小”)。 这两个是通过使用Box
解决的,它也可以用生命周期进行注释:
impl<'a> Iterator for Quads<'a> {
type Item = Box<dyn Iterator<Item = u32> + 'a>;
fn next(&mut self) -> Option<Self::Item> {
...
}
}
另一个问题是,即使mx
的使用是只读的,闭包|(x, y)| self.mx[y][x]
|(x, y)| self.mx[y][x]
捕获self
,它是一个可变引用。 这很简单:获取一个局部变量,然后move
:
let mx = self.mx;
Some(Box::new(...
.map(move |(x, y)| mx[y as usize][x as usize])))
差点忘了。 还有一个非常奇怪的,即使我最初输入它看起来也很可疑: step_by
usize
,它是无符号的,并没有真正构造一个通过添加给定增量来枚举值的Range
; 相反,它构造了一个跳过给定数量元素(几乎)的Iterator
。 因此,需要一个元组迭代器:
struct Tup<T> {
x: (T, T),
d: (T, T),
}
...
impl<T: AddAssign + Copy> Iterator for Tup<T> {
type Item = (T, T);
fn next(&mut self) -> Option<(T, T)> {
self.x.0 += self.d.0;
self.x.1 += self.d.1;
Some(self.x)
}
}
因此,不是使用step_by
压缩两个Iterator
,您会得到一个用已知初始值和增量初始化的Tup
:
Some(Box::new(Tup::new((x, y), (self.dx, self.dy))
.take(4)
.map(move |(x, y)| mx[y as usize][x as usize])))
另一种解决方案不是导出迭代器,而是传递一个操作以在内部运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.