如何在match分支中分配给match表达式中使用的变量? [英] How to assign to the variable used in match expression inside a match branch?
问题描述
我正在尝试实现一个通用功能join()
,该功能可以在任何迭代器的迭代器上工作.我在next()
方法实现内的match
表达式中的借位检查器遇到问题.这是我的代码的简化版本:
I'm trying to implement a general function join()
that can work on any iterator of iterators. I have a problem with the borrow checker in a match
expression inside the next()
method implementation. Here is a simplified version of my code:
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
我理解为什么借用检查器抱怨我的代码,但是我没有找到一个好的解决方案,只有一个丑陋的解决方法:
I understand why the borrow checker complains about my code, but I did not find a good solution, only an ugly workaround:
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; }
}
}
}
我想像这样的情况经常发生.我该如何重写我的代码来处理或避免使用它们?
I imagine that situations like this occur regularly; how can I rewrite my code to deal with them or avoid them?
推荐答案
以下是该问题的简单再现:
Here is a simpler reproduction of the problem:
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的借阅检查器的弱点.启用非词汇生存期时,此
This is a weakness of the AST-based borrow checker. When non-lexical lifetimes are enabled, this works as-is. The enhanced MIR-based borrow checker can see that there's no borrow of the matched-on variable at the point at which you try to replace it.
For what it's worth, your join
is just a flat_map
:
input.iter().flat_map(|x| x)
或 flatten
:
input.iter().flatten()
You can see how these implement next
for another idea:
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
借来的.
This clearly delineates that the iterator value doesn't really borrow from inner_iter
.
Without looking at flatten
, I would have chosen to clearly indicate that there's no overlapping borrowing by taking the Option
and restoring it if it is Some
, as you've done:
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;
}
}
这篇关于如何在match分支中分配给match表达式中使用的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!