匹配后如何修改值?

时间:2016-08-08 16:03:32

标签: rust borrow-checker

我试图走一对迭代器。这在概念上看起来非常微不足道,但实际上却没有表达出来。

fn next(&mut self) -> Option<Self::Item> {
    let mut left = self.left.next();
    let mut right = self.right.next();

    loop {
        match (left, right) {
            (Some(left_value), Some(right_value)) => {
                match left_value.cmp(&right_value) {
                    Ordering::Equal => return Some((left_value, right_value)),
                    Ordering::Less => left = self.left.next(),
                    Ordering::Greater => right = self.right.next(),
                }
            }

            _ =>  return None
        }
    }
}

这不起作用,因为当我匹配时左右移动。有什么方法可以成功表达这一点?

示例(也称为整个箱子):

use std::cmp::{Eq, Ord, Ordering};

pub trait AscendingIterator: Iterator where <Self as Iterator>::Item: Eq + Ord {}

pub trait DescendingIterator: Iterator where <Self as Iterator>::Item: Eq + Ord {}

pub struct AscendingIntersection<T, T1, T2>
    where T: Eq + Ord,
          T1: AscendingIterator<Item = T>,
          T2: AscendingIterator<Item = T>
{
    left: T1,
    right: T2,
}

impl<T, T1, T2> Iterator for AscendingIntersection<T, T1, T2>
    where T: Eq + Ord,
          T1: AscendingIterator<Item = T>,
          T2: AscendingIterator<Item = T>
{
    type Item = (T, T);

    fn next(&mut self) -> Option<Self::Item> {
        let mut left = self.left.next();
        let mut right = self.right.next();

        loop {
            match (left, right) {
                (Some(left_value), Some(right_value)) => {
                    match left_value.cmp(&right_value) {
                        Ordering::Equal => return Some((left_value, right_value)),
                        Ordering::Less => left = self.left.next(),
                        Ordering::Greater => right = self.right.next(),
                    }
                }

                _ => return None,
            }
        }
    }
}

编辑:我为这个懒惰的例子道歉;我可以做的打字数量受到无关的骑车伤害的限制。

1 个答案:

答案 0 :(得分:2)

您的match (left, right)移出leftright的值,因此在下一次迭代中它们为空。那么为什么不把它们搬回去呢?

Ordering::Less => {
    left = self.left.next();
    right = Some(right_value);
},
Ordering::Greater => {
    left = Some(left_value);
    right = self.right.next();
},

现在,这仍然有点难看。一个更好的方法是完全删除match。先窃取try_opt! - 我使用了http://crumblingstatue.github.io/doc/try_opt/src/try_opt/lib.rs.html#1-37

macro_rules! try_opt {
    ($e:expr) =>(
        match $e {
            Some(v) => v,
            None => return None,
        }
    )
}

然后就这样做

let mut left = try_opt!(self.left.next());
let mut right = try_opt!(self.right.next());

loop {
    match left.cmp(&right) {
        Ordering::Equal => return Some((left, right)),
        Ordering::Less => left = try_opt!(self.left.next()),
        Ordering::Greater => right = try_opt!(self.right.next()),
    }
}