Rust impl Iterator for Range<T> on custom type

Rust impl Iterator for Range<T> on custom type

我有一个点结构,像这样:

#[derive(Clone, Copy, Debug)]
struct Point {
  x: i32,
  y: i32,
}

我想像这样在点之间迭代:

let start = Point { x: 0, y: 0 };
let end = Point { x: 3, y: 3 };
for p in start..end {
  // p should be
  // (0, 0)
  // (1, 0)
  // (2, 0)
  // (0, 1)
  // (1, 1)
  // (2, 1)
  // (0, 2)
  // etc
}

Playground.

但是,我似乎无法实现这一点。 start..end 产生一个 Range<Pos>,这是标准库中的一个类型。所以我无法自定义 impl Iterator for Range<Pos>,因为这些类型中的 none 在当前板条箱中。

我也不能 impl Step for Point,因为迭代器必须知道范围的开始和结束。 Step 不会给你这个信息。

最后,我无法为 Iterator 编写包装器,因为 impl MyIterator for Range<Point> 会失败并出现错误,指出 Point 未实现 Step

有什么办法可以解决吗?我目前的解决方案是在Point上定义一个to函数,这样你就可以这样写:

for p in start.to(end) {
  // works as expected
}

to 函数生成一个自定义迭代器,它可以满足我的需求。但是,我仍然想使用 .. 语法。

编辑:AFAIK,this 是它工作所需要的。根据这些评论,这看起来不可能。

正如您发现的那样,您不能直接执行此操作。但是,我不会太在意语法,因为 point..point 不一定会使代码更具可读性。事实上,它隐藏了有关排序的信息,并使以后添加按列顺序而不是行顺序的迭代器变得更加困难。

传达顺序的设计,同时仍然使用范围语法可以是:

fn row_major(range: Range<Point>) -> impl Iterator<Item = Point> {
    (range.start.y..range.end.y)
        .flat_map(move |y| (range.start.x..range.end.x).map(move |x| Point { x, y }))
}

fn main() {
    let start = Point { x: 0, y: 0 };
    let end = Point { x: 2, y: 2 };
    let result: Vec<_> = row_major(start..end).collect();

    assert_eq!(
        result,
        vec![
            Point { x: 0, y: 0 },
            Point { x: 1, y: 0 },
            Point { x: 0, y: 1 },
            Point { x: 1, y: 1 },
        ]
    )
}

row_major 可能不是最佳名称,具体取决于您的应用程序。其他选项如 horizontal_iterhrangeiter_rows。给它一个这样的名字可以让 reader 清楚地知道期望的顺序,并且还可以在以后添加函数的对称列主(垂直)版本。

您还可以扩展它以支持 ..endstart..=end 变体以获得更多表现力,同时排除此处没有意义的 start..