当前位置: 首页 > 知识库问答 >
问题:

预计std::iter::Iterator,但std::iter::Iterator找到

羿季
2023-03-14

我试图表达以下观点:

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

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,它是一个迭代器,可以从欧拉问题中提取四倍数,其中每个四倍数本身就是一个迭代器

< code>Quad中的所有内容都表示< code >迭代器的状态。< code>xs和< code>ys表示“当前单元格”坐标的迭代器,从这里开始下一个四元组。< code>next然后尝试查看是否到达行尾,并通过将< code>xs重新初始化到新的< code >迭代器来前进到下一行。当< code>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 }

我想我已经抓住了这个想法,但我不知道编译器不喜欢它的什么,因此如何前进。

共有2个答案

郎刚捷
2023-03-14

另一种解决方案是不导出迭代器,而是传递一个操作在内部运行。

令狐钧
2023-03-14

好吧,我想出来了。rustc产生了这样一条令人困惑的错误消息,这确实没有什么帮助-显然,它找到了它想要的,但仍然不满意。

发布的代码存在几个问题。我最初的假设是,通过将引用标记为可变,我可以告诉编译器,从此以后,无论谁收到引用,都要对它负责,包括内存管理。虽然在某些情况下它可能是真的(我不确定;这还有待解决),但它肯定不适用于结构字段(Quadxs)和返回值。在这种情况下,我们可以摆脱

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] 捕获 self,这是一个可变引用。这是一个简单的方法:获取一个局部变量,然后移动

  let mx = self.mx;
  Some(Box::new(...
          .map(move |(x, y)| mx[y as usize][x as usize])))

差点忘了。还有一个非常奇怪的,甚至在我最初输入时看起来很可疑:<code>step_by

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)
   }
}

因此,您将获得一个使用已知初始值和增量初始化的Tup,而不是使用step_by压缩两个迭代

  Some(Box::new(Tup::new((x, y), (self.dx, self.dy))
                     .take(4)
                     .map(move |(x, y)| mx[y as usize][x as usize])))

 类似资料:
  • Iterator::find 是一个函数,在处理一个迭代器(iterator)时,将返回第一个满足条件的元素作为一个 Option 类型。它的原型如下: pub trait Iterator { // 迭代相关的类型。 type Item; // `find` 接受 `&mut self` 作为调用者可能被借用和修改,但不会消费掉。 // (原文:`find` ta

  • Iterator::any 是一个函数,在处理一个迭代器(iterator)时,当其中任一元素符合条件(predicate)时将返回 true,否则返回 false。它的原型如下: pub trait Iterator { // 迭代相关的类型(原文:The type being iterated over)。 type Item; // `any` 接受 `&mut se

  • This module implements a werkzeug.contrib.iterio.IterIO" title="werkzeug.contrib.iterio.IterIO that converts an iterator into a stream object and the other way round. Converting streams into iterators

  • 我正在编写Rust by Example教程,其中包含以下代码片段: 我完全混淆了-对于,从返回的迭代器产生引用,从产生值,但对于数组,这些迭代器是相同的? 这两种方法的用例/API是什么?

  • 本文向大家介绍Python-iter()方法,包括了Python-iter()方法的使用技巧和注意事项,需要的朋友参考一下 Python基本上创建了一个迭代器对象,该对象可用于迭代可迭代对象。让我们尝试了解什么是迭代器和可迭代对象。迭代器-迭代器是一个对象,其中包含可在迭代对象上迭代的可数数量的值。可迭代的:可迭代的基本上是数据类型的集合,例如列表,元组或字符串。 语法: iter(对象,前哨)

  • 迭代器设计模式属于行为设计模式类别。 开发人员几乎在每种编程语言中都遇到了迭代器模式。 此模式的使用方式有助于以顺序方式访问集合(类)的元素,而无需了解底层设计。 如何实现迭代器模式? 我们现在将看到如何实现迭代器模式。 import time def fib(): a, b = 0, 1 while True: yield b a, b = b, a + b