我正在尝试实现一个可以在迭代器的任何迭代器上工作的通用函数join()
。我在match
方法实现中的next()
表达式中的借用检查器有问题。这是我的代码的简化版本:
pub struct Join<I>
where
I: Iterator,
I::Item: IntoIterator,
{
outer_iter: I,
inner_iter: Option<<I::Item as IntoIterator>::IntoIter>,
}
impl<I> Join<I>
where
I: Iterator,
I::Item: IntoIterator,
{
pub fn new(mut iter: I) -> Join<I> {
let inner_iter = iter.next().map(|it| it.into_iter());
Join {
outer_iter: iter,
inner_iter,
}
}
}
impl<I> Iterator for Join<I>
where
I: Iterator,
I::Item: IntoIterator,
{
type Item = <I::Item as IntoIterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
loop {
match &mut self.inner_iter {
Some(ref mut it) => match it.next() {
Some(x) => {
return Some(x);
}
None => {
self.inner_iter = self.outer_iter.next().map(|it| it.into_iter());
}
},
None => {
return None;
}
}
}
}
}
pub trait MyItertools: Iterator {
fn join(self) -> Join<Self>
where
Self: Sized,
Self::Item: IntoIterator,
{
Join::new(self)
}
}
impl<I> MyItertools for I where I: Iterator {}
#[cfg(test)]
mod test {
use super::MyItertools;
#[test]
fn it_works() {
let input = [[1], [2]];
let expected = [&1, &2];
assert_eq!(input.iter().join().collect::<Vec<_>>(), expected);
}
}
错误文字:
error[E0506]: cannot assign to `self.inner_iter` because it is borrowed
--> src/main.rs:39:25
|
33 | match &mut self.inner_iter {
| --------------- borrow of `self.inner_iter` occurs here
...
39 | self.inner_iter = self.outer_iter.next().map(|it| it.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.inner_iter` occurs here
我理解为什么借用检查器会抱怨我的代码,但我没有找到一个好的解决方案,只有一个丑陋的解决方法:
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.inner_iter.take() {
Some(mut it) => {
match it.next() {
Some(x) => { self.inner_iter = Some(it); return Some(x); }
None => { self.inner_iter = self.outer_iter.next().map(|it| it.into_iter()); }
}
}
None => { return None; }
}
}
}
我想像这样的情况经常发生;如何重写我的代码来处理它们或避免它们?
这是一个更简单的问题再现:
fn main() {
let mut a = (42, true);
match a {
(ref _i, true) => a = (99, false),
(ref _i, false) => a = (42, true),
}
println!("{:?}", a);
}
error[E0506]: cannot assign to `a` because it is borrowed
--> src/main.rs:4:27
|
4 | (ref _i, true) => a = (99, false),
| ------ ^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here
| |
| borrow of `a` occurs here
error[E0506]: cannot assign to `a` because it is borrowed
--> src/main.rs:5:28
|
5 | (ref _i, false) => a = (42, true),
| ------ ^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here
| |
| borrow of `a` occurs here
这是基于AST的借用检查器的弱点。启用non-lexical lifetimes时,这个works as-is。增强的基于MIR的借用检查器可以看到在您尝试替换它时,没有借用匹配变量。
对于它的价值,你的join
只是一个flat_map
:
input.iter().flat_map(|x| x)
或者flatten
:
input.iter().flatten()
你可以看到这些implement next
如何为另一个想法:
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(v) = self.inner_iter.as_mut().and_then(|i| i.next()) {
return Some(v);
}
match self.outer_iter.next() {
Some(x) => self.inner_iter = Some(x.into_iter()),
None => return None,
}
}
}
这清楚地描述了迭代器值并不真正从inner_iter
借用。
没有看flatten
,我会选择清楚地表明taking Option
没有重叠借用,如果它是Some
则恢复它,就像你做的那样:
match self.inner_iter.take() {
Some(mut it) => match it.next() {
Some(x) => {
self.inner_iter = Some(it);
return Some(x);
}
None => {
self.inner_iter = self.outer_iter.next().map(|it| it.into_iter());
}
},
None => {
return None;
}
}
在这种情况下,我发现将代码编写成两部分很有用:首先收集数据,然后更新mutable:
fn next(&mut self) -> Option<Self::Item> {
loop {
//collect the change into a local variable
let ii = match &mut self.inner_iter {
Some(ref mut it) => {
match it.next() {
Some(x) => { return Some(x); }
None => self.outer_iter.next().map(|it| it.into_iter())
}
}
None => { return None; }
};
//self.inner_iter is no longer borrowed, update
self.inner_iter = ii;
}
}
所有不修改inner_iter
的分支执行return
的事实使代码更容易。