在Rust中,如何创建可变的迭代器?

巴纳比道尔顿(Barnaby Dalton):

尝试在安全的Rust中创建可变的迭代器时,我的生存期遇到了困难。

这是我将问题简化为的内容:

struct DataStruct<T> {
    inner: Box<[T]>,
}

pub struct IterMut<'a, T> {
    obj: &'a mut DataStruct<T>,
    cursor: usize,
}

impl<T> DataStruct<T> {
    fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { obj: self, cursor: 0 }
    }
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let i = f(self.cursor);
        self.cursor += 1;
        self.obj.inner.get_mut(i)
    }
}

fn f(i: usize) -> usize {
   // some permutation of i
}

我的结构DataStruct永远不会改变,但是我需要能够对存储在其中的元素的内容进行变异。例如,

let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
  *x += 1;
}

编译器给我一个关于我要返回的引用的生存期冲突的错误。它发现我期望的寿命不是该next(&mut self)函数的范围

如果我尝试在上注释生命周期next(),则编译器会告诉我我不满足Iterator特性。这可以安全地解决锈蚀吗?

这是错误:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/iter_mut.rs:25:24
   |
25 |         self.obj.inner.get_mut(i)
   |                        ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 22:5...
  --> src/iter_mut.rs:22:5
   |
22 | /     fn next(&mut self) -> Option<Self::Item> {
23 | |         let i = self.cursor;
24 | |         self.cursor += 1;
25 | |         self.obj.inner.get_mut(i)
26 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/iter_mut.rs:25:9
   |
25 |         self.obj.inner.get_mut(i)
   |         ^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 19:6...
  --> src/iter_mut.rs:19:6
   |
19 | impl<'a, T> Iterator for IterMut<'a, T> {
   |      ^^
note: ...so that the types are compatible
  --> src/iter_mut.rs:22:46
   |
22 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
23 | |         let i = self.cursor;
24 | |         self.cursor += 1;
25 | |         self.obj.inner.get_mut(i)
26 | |     }
   | |_____^
   = note: expected  `std::iter::Iterator`
              found  `std::iter::Iterator`

编辑

  • 更改了实现,next()使迭代顺序是原始序列的排列。
彼得·霍尔:

借用检查器无法证明对的后续调用next()不会访问相同的数据。之所以会出现问题,是因为借用的生命周期是迭代器生命周期的持续时间,因此无法证明不会在同一时间同时引用同一数据的两个可变引用。

如果没有不安全的代码,或者更改数据结构,确实没有办法解决此问题。您可以进行以下操作的等效项,slice::split_at_mut但是,由于您无法对原始数据进行突变,因此无论如何都必须在不安全的代码中实现该功能。一个不安全的实现可能看起来像这样:

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.cursor;
        self.cursor += 1;
        if i < self.obj.inner.len() {
            let ptr = self.obj.inner.as_mut_ptr();
            unsafe {
                Some(&mut *ptr.add(i))
            }
        } else {
            None
        }
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在Rust中返回链式迭代器

如何在Java中创建自定义迭代器?

如何避免在Rust中为可变和不可变引用编写重复的访问器函数?

如何使用返回可变引用的迭代器创建自己的数据结构?

如何组成可变的迭代器?

在Java中创建迭代器

在Rust中,向量是迭代器吗?

如何实现支持可变迭代器的容器?

如何跳过Rust迭代器中的第N个元素?

如何在Rust中返回盒装可克隆迭代器?

如何使用Rust从stdin创建一个高效的char迭代器?

如何在Rust中解释对可变类型的不可变引用?

如何在Python中的字母上创建循环迭代器?

如何在Rust中定义一个包含可迭代项的结构上的迭代器?

如何在Rust中延长迭代器适配器内部临时变量的寿命?

如何在不使用可变变量的情况下在Scala中编程迭代器?

如何创建一个迭代器,该迭代器生成由Rust中的索引列表指定的集合元素?

Python中的可变迭代器?

如何在Rust中迭代宏的参数?

在Rust中如何借用可变与可变?

在Rust中迭代时如何调用方法

在迭代器上创建方法,该方法在Rust中返回迭代器

如何在结构字段上创建可变的迭代器

Rust中的迭代器类型

如何在Rust中为引用创建一个“可迭代”特征?

Rust实现迭代器

如何在Rust中修复“ ..在循环的上一迭代中是在这里可变地借用的”?

如何创建迭代次数可变的for循环?

在 Frida 中迭代集合 - 创建迭代器