gpt4 book ai didi

rust - 如何分配给匹配分支内的匹配表达式中使用的变量?

转载 作者:行者123 更新时间:2023-11-29 08:10:29 27 4
gpt4 key购买 nike

我正在尝试实现一个通用函数 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 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 的借用检查器可以看到在您尝试替换匹配变量时没有借用它。


就其值(value)而言,您的 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;
}
}

关于rust - 如何分配给匹配分支内的匹配表达式中使用的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51027517/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com