我正在尝试为类型为vector的向量创建一个可变迭代器: Vec<Vec<(K, V)>>
迭代器代码:
pub struct IterMut<'a, K: 'a, V: 'a> {
iter: &'a mut Vec<Vec<(K, V)>>,
ix: usize,
inner_ix: usize,
}
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
while self.iter.len() < self.ix {
while self.iter[self.ix].len() < self.inner_ix {
self.inner_ix += 1;
let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
return Some((&k, &mut v));
}
self.ix += 1;
}
return None;
}
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:16:42
|
16 | let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
| ^^^^^^^^^^^^^^^^^^
|
help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<(&'a K, &'a mut V)>
--> src/main.rs:11:5
|
11 | fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
| ^
Run Code Online (Sandbox Code Playgroud)
显然我有生命问题,但我不知道如何告诉编译器这应该有效.
这是你应该如何实现可变迭代器还是有更好的方法?
在调试神秘的错误消息时,我发现尽可能地尝试隔离问题更容易.
第一步是将表达式分解为其基本组成部分,让我们从分割索引步骤开始:
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
while self.iter.len() < self.ix {
while self.iter[self.ix].len() < self.inner_ix {
self.inner_ix += 1;
let outer: &'a mut Vec<_> = self.iter;
let inner: &'a mut Vec<_> = &mut outer[self.ix];
let (ref k, ref mut v) = inner[self.inner_ix];
return Some((&k, &mut v));
}
self.ix += 1;
}
return None;
}
Run Code Online (Sandbox Code Playgroud)
该Index特性假设其输出的生命周期与其接收器的生命周期相关联,因此为了获得'a一生,我们需要接收器具有&'a生命周期,并且它向上传播,从而导致上述代码.
但是这里有一个问题:let outer: &'a mut Vec<_> = self.iter;不会编译,因为可变引用不是Copy.
那么,如何从可变引用获得可变引用(这必须是可能的,因为IndexMut获得可变引用)?
一个人使用再借款:let outer: &'a mut Vec<_> = &mut *self.iter;.
哦,哦:
Run Code Online (Sandbox Code Playgroud)error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> <anon>:16:45 | 16 | let outer: &'a mut Vec<_> = &mut *self.iter; | ^^^^^^^^^^^^^^^ |
重新借用的参考无效'a,仅对(未命名)生命周期有效self!
为什么生锈?为什么?
因为否则会不安全.
&mut T 保证不会出现别名,但是您的方法可能会创建别名引用(如果您忘记推进索引):
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
return Some((&k, &mut v));
}
Run Code Online (Sandbox Code Playgroud)
即使你不这样做,也不能保证你没有一种rewind允许"退后"的方法.
TL; DR:你即将踩到地雷,你被转向Stack Overflow;)
好吧,但是你如何实现迭代器!.
当然,使用迭代器.正如Shepmaster(简要地)回答的那样,标准库中已经有了相同的东西FlatMap.诀窍是使用现有的迭代器来获取细节!
就像是:
use std::slice::IterMut;
pub struct MyIterMut<'a, K: 'a, V: 'a> {
outer: IterMut<'a, Vec<(K, V)>>,
inner: IterMut<'a, (K, V)>,
}
Run Code Online (Sandbox Code Playgroud)
然后inner只要它提供项目就消耗掉,而当它为空时你从中重新填充outer.
impl<'a, K, V> MyIterMut<'a, K, V> {
fn new(v: &'a mut Vec<Vec<(K, V)>>) -> MyIterMut<'a, K, V> {
let mut outer = v.iter_mut();
let inner = outer.next()
.map(|v| v.iter_mut())
.unwrap_or_else(|| (&mut []).iter_mut());
MyIterMut { outer: outer, inner: inner }
}
}
impl<'a, K, V> Iterator for MyIterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
loop {
match self.inner.next() {
Some(r) => return Some((&r.0, &mut r.1)),
None => (),
}
match self.outer.next() {
Some(v) => self.inner = v.iter_mut(),
None => return None,
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
快速测试案例:
fn main() {
let mut v = vec![
vec![(1, "1"), (2, "2")],
vec![],
vec![(3, "3")]
];
let iter = MyIterMut::new(&mut v);
let c: Vec<_> = iter.collect();
println!("{:?}", c);
}
Run Code Online (Sandbox Code Playgroud)
打印:
Run Code Online (Sandbox Code Playgroud)[(1, "1"), (2, "2"), (3, "3")]
如预期,所以它不是完全打破,但我希望我没有依靠的&[]是'static技巧(即,std::slice::IterMut执行Default).
| 归档时间: |
|
| 查看次数: |
432 次 |
| 最近记录: |