Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 迭代器返回的对象中的可变引用_Rust - Fatal编程技术网

Rust 迭代器返回的对象中的可变引用

Rust 迭代器返回的对象中的可变引用,rust,Rust,我想创建一个迭代器,该迭代器也能够公开相邻的项。只要我不想也改变这些项目,这是好的和容易的。但如何使同一结构的可变变体 不变的: struct NearestNeighbours2D<'a, T> { mid: &'a T, left: &'a T, right: &'a T, top: &'a T, bot: &'a T, } struct EnumerateNearestNeighbours2D&l

我想创建一个
迭代器
,该迭代器也能够公开相邻的项。只要我不想也改变这些项目,这是好的和容易的。但如何使同一结构的可变变体

不变的:

struct NearestNeighbours2D<'a, T> {
    mid: &'a T,
    left: &'a T,
    right: &'a T,
    top: &'a T,
    bot: &'a T,
}

struct EnumerateNearestNeighbours2D<'a, I>
where I: std::ops::Index<usize> {
    x: usize,
    y: usize,
    width: usize,
    height: usize,
    inner: &'a I
}

impl<'a, I: std::ops::Index<usize>> Iterator for EnumerateNearestNeighbours2D<'a, I>
where <I as std::ops::Index<usize>>::Output: std::marker::Sized {
    
    type Item = NearestNeighbours2D<'a, I::Output>;
    fn next(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item> {

        let (top, left, mid, right, bot) = (
            (self.y - 1) * self.width + self.x,
            self.y * self.width + self.x - 1,
            self.y * self.width + self.x,
            self.y * self.width + self.x + 1,
            (self.y + 1) * self.width + self.x,
        );

        Some(
            NearestNeighbours2D {
                mid: &self.inner[mid],
                left: &self.inner[left],
                right: &self.inner[right],
                top: &self.inner[top],
                bot: &self.inner[bot],
            }
        )
    }
}

不幸的是,
EnumerateNearestNears2DMUT
无法正确生成,这是不合理的。每次调用
next
都会得到
&mut
引用,这些引用可能与上次调用
next
返回的
&mut
引用重叠。这意味着,如果它起作用,它将通过创建别名
&mut
s来违反引用规则

这与有一个相同的原因,但没有
WindowsMut
(尽管
ChunksMut
是可以的,因为块是不重叠的)

有些问题()给出了类似的错误消息,但实际上是可以解决的(在某些情况下是不安全的),因为所引用的项实际上是不重叠的。这些解决方案在这里行不通。如果你可以(一个“流迭代器”),这个API就可以被完善。但是,
Iterator
不允许这样做

这里有三种可能的选择。当然还有其他的

  • 根本不允许可变迭代(使用邻居)。只需通过共享(
    &
    )引用公开迭代,如果需要修改原始网格,则创建一个修改后的副本,并在完成迭代后将其与原始网格交换。不管怎样,这通常是您想要的,如果您正在编写图像过滤器或细胞自动机之类的东西,其中每个输出都依赖于多个输入

  • 接受闭包并在API中使用内部迭代,而不是外部迭代。因此,不要像这样:

    for neighbors in array.enumerate_2d_neighbors_mut() {
        println!("{}", neighbors.top);
    }
    
    array.foreach_2d_neighbors_mut(|neighbors| {
        println!("{}", neighbors.top);
    });
    
    你可以这样写:

    for neighbors in array.enumerate_2d_neighbors_mut() {
        println!("{}", neighbors.top);
    }
    
    array.foreach_2d_neighbors_mut(|neighbors| {
        println!("{}", neighbors.top);
    });
    
    在这种情况下,对
    数组
    项的引用在
    foreach\u 2d\u neights\u mut
    方法内的
    for
    循环中进行,并且不转义它。即使没有
    safe
    代码,也可以非常轻松地编写此API

  • 使用内部可变性(
    单元格
    参考单元格
    原子???
    等)通过
    引用进行变异,而不需要
    &mut
    。取决于你在做什么,这可能是正确的方法。要知道你可以。然而,在大多数情况下,这并不是我的第一选择


@trentcl你能不能也看看这个?仅供参考,人们不会收到评论中被@ed的通知,除非他们是被评论文章的作者或之前对同一篇文章发表过评论。但我碰巧在这里,所以我要看一看:-)我在谷歌上搜索了
Cell
,它指出的第一件事就是我犯的错误:“[…]只可能有以下之一:对对象有几个不可变的引用(&T)(也称为别名)。对对象有一个可变引用(&mut)(也称为易变性)。”。我只在读取时需要它来“混合”相邻元素并保存在不同的缓冲区中,但我想知道“如果”会怎样,以防将来需要它:D