如何分配给匹配分支内的匹配表达式中使用的变量?
How to assign to the variable used in match expression inside a match branch?
我正在尝试实现一个通用函数 join()
,它可以在迭代器的任何迭代器上工作。 next()
方法实现中的 match
表达式中的借用检查器有问题。这是我的代码的简化版本:
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 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
使得代码更简单。
这里是问题的简单重现:
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 are enabled, this 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;
}
}
我正在尝试实现一个通用函数 join()
,它可以在迭代器的任何迭代器上工作。 next()
方法实现中的 match
表达式中的借用检查器有问题。这是我的代码的简化版本:
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 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
使得代码更简单。
这里是问题的简单重现:
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 are enabled, this 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;
}
}