Rust 如何分配到匹配分支内的匹配表达式中使用的变量?

Rust 如何分配到匹配分支内的匹配表达式中使用的变量?,rust,match,lifetime,borrow-checker,Rust,Match,Lifetime,Borrow Checker,我正在尝试实现一个通用函数join(),它可以在迭代器的任何迭代器上工作。我在next()方法实现中的match表达式中遇到借用检查器问题。以下是我的代码的简化版本: pub struct Join<I> where I: Iterator, I::Item: IntoIterator, { outer_iter: I, inner_iter: Option<<I::Item as IntoIterator>::IntoIter>

我正在尝试实现一个通用函数
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);
    }
}
我理解为什么借用检查器抱怨我的代码,但我没有找到一个好的解决方案,只有一个丑陋的解决方法:

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下一步(&mut self)->选项{
环路{
匹配self.inner_iter.take(){
一些(mut it)=>{
匹配它。下一个(){
Some(x)=>{self.inner_iter=Some(it);返回Some(x);}
None=>{self.inner_iter=self.outer_iter.next().map(| it | it.into_iter());}
}
}
None=>{返回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;
    }
}
fn下一步(&mut self)->选项{
环路{
//将更改收集到局部变量中
设ii=匹配和多个内部{
一些(参考mut it)=>{
匹配它。下一个(){
Some(x)=>{返回Some(x);}
None=>self.outer_iter.next().map(| it | it.into_iter())
}
}
None=>{返回None;}
};
//self.internal_iter不再被借用,请更新
自内电阻=ii;
}
}

事实上,所有不修改
内部代码的分支都执行
返回
,这使得代码变得更容易。

在这种情况下,我发现将代码分为两部分很有用:首先收集数据,然后更新可变数据:

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;
    }
}
fn下一步(&mut self)->选项{
环路{
//将更改收集到局部变量中
设ii=匹配和多个内部{
一些(参考mut it)=>{
匹配它。下一个(){
Some(x)=>{返回Some(x);}
None=>self.outer_iter.next().map(| it | it.into_iter())
}
}
None=>{返回None;}
};
//self.internal_iter不再被借用,请更新
自内电阻=ii;
}
}

事实上,所有不修改
内部代码的分支都执行
返回
,这使得代码变得更容易。

下面是问题的简单再现:

fn main() {
    let mut a = (42, true);
    match a {
        (ref _i, true) => a = (99, false),
        (ref _i, false) => a = (42, true),
    }
    println!("{:?}", a);
}
错误[E0506]:无法分配给'a',因为它是借用的
-->src/main.rs:4:27
|
4 |(参考i,真)=>a=(99,假),
|----^^^^^^^^^^^^此处发生借来的'a'的赋值
|          |
|a的借词出现在这里
错误[E0506]:无法分配给'a',因为它是借用的
-->src/main.rs:5:28
|
5 |(参考i,假)=>a=(42,真),
|----^^^^^^^^^^^此处发生借来的'a'的赋值
|          |
|a的借词出现在这里
这是基于AST的借用检查器的一个弱点。启用时,此选项将被禁用。增强的基于MIR的借用检查器可以看到,在尝试替换匹配的on变量时,该变量没有借用


无论如何,您的
加入
只是一个:

或:

您可以看到这些是如何用于另一个想法的:

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,
        }
    }
}

下面是问题的简单再现:

fn main() {
    let mut a = (42, true);
    match a {
        (ref _i, true) => a = (99, false),
        (ref _i, false) => a = (42, true),
    }
    println!("{:?}", a);
}
错误[E0506]:无法分配给'a',因为它是借用的
-->src/main.rs:4:27
|
4 |(参考i,真)=>a=(99,假),
|----^^^^^^^^^^^^此处发生借来的'a'的赋值
|          |
|a的借词出现在这里
错误[E0506]:无法分配给'a',因为它是借用的
-->src/main.rs:5:28
|
5 |(参考i,假)=>a=(42,真),
|----^^^^^^^^^^^此处发生借来的'a'的赋值
|          |
|a的借词出现在这里
这是基于AST的借用检查器的一个弱点。启用时,此选项将被禁用。增强的基于MIR的借用检查器可以看到,在尝试替换匹配的on变量时,该变量没有借用


无论如何,您的
加入
只是一个:

或:

您可以看到这些是如何用于另一个想法的:

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,
        }
    }
}

您也可以这样做:
self.inner\u iter=match&mut self.inner\u iter{…}。从匹配表达式中提取赋值是满足借用检查器要求的。在这种情况下,是否使用局部变量仅仅关系到可读性。您还可以这样做:
self.inner\u iter=match&mut self.inner\u iter{…}。从匹配表达式中提取赋值是满足借用检查器要求的。在这种情况下,是否使用局部变量仅仅关系到可读性。