gpt4 book ai didi

rust - 预期的std::iter::Iterator,但找到了std::iter::Iterator

转载 作者:行者123 更新时间:2023-12-03 11:29:09 29 4
gpt4 key购买 nike

我正在尝试表达以下内容:

给定一个矩阵和两个索引增量,返回矩阵中所有数字的四倍体:沿行,列或对角线的四倍体。

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,可以从该Euler问题中提取四倍的数字,其中每个四倍数本身就是 Iterator
Quad内的所有内容均表示 Iterator的状态。 xsys表示“当前单元格”的坐标的迭代器,从该迭代器开始下一个四元组。然后, 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字段(Quadxs)并返回值。在这种情况下,我们可以在&mutxs的声明中摆脱ys:

struct Quads<'a> {
mx: &'a Vec<Vec<u32>>,
xs: Peekable<Range<i32>>,
ys: Peekable<Range<i32>>,
dx: i32,
dy: i32,
}

另一个问题是,如果它不是引用,则如何限制值的生存期。 (例如,在这种情况下, Iterator返回的 next仅在 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]也会捕获 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)
}
}

因此,您无需使用 Iterator压缩两个 step_by,而是使用已知的初始值和增量初始化了一个 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])))

关于rust - 预期的std::iter::Iterator,但找到了std::iter::Iterator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59551596/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com