我在尝试创建一个安全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
}
我的数据结构的结构不会改变,但我需要能够修改其中存储的元素内容。例如,
let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
*x += 1;
}
编译器提示我返回的引用存在生命周期冲突错误。它发现的生命周期不符合我预期的是
next(&mut self)
函数的作用域。如果我试图在
next()
上注释生命周期,则编译器会告诉我未满足迭代器特性。在Safe Rust中是否可以解决这个问题?以下是错误信息:
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()
的实现方式,使得迭代顺序是原始序列的置换。
slice::IterMut
之所以使用unsafe
实现,正是出于这个原因。如果可以的话,我鼓励你创建一个别名或包装slice::IterMut
,而不是编写自己的代码。 - trentself.cursor
永远不会是相同的值?如果答案是“除了调用next()
之外没有改变cursor
的方法”,那么为什么不能只是包装slice::IterMut
呢? - trentlet i = f(self.cursor)
,其中 f 是索引的置换。 - Barnaby Daltonf
,self.cursor
和[T] :: index
)你知道但编译器不知道,如果它们被破坏了,你的代码就会有未定义的行为,这正是你需要使用unsafe
的时候。 - trent