Change selector in match when selector is a mutable reference

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-04 04:08:24

问题


I want to change enum variant based on some properties of the current enum variant in Iterator::next. I have two attempts, neither of which compile:

enum Test {
    A(Vec<usize>),
    B,
}

impl<'a> Iterator for Test {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        // attempt 1
        if let Test::A(ref a) = *self {
            if a.len() == 0 {
                *self = Test::B; // doesn't work because a is borrowed
            };
        }

        // attempt 2
        *self = match *self {
            Test::A(ref a) if a.len() == 0 => Test::B,
            _ => *self, // cannot move out of borrowed context
        };
        None
    }
}

fn main() {}

My second attempt does work if I am not working with references in the selector:

let mut a = Test::A(vec![]);
a = match a {
    Test::A(ref a) if a.len() == 0 => Test::B,
    _ => a,
};

This question is related to Is there a way to use match() in rust when modifying the selector?, but the solution proposed there is not generic: it only works if the same function is executed in both branches.

What is the Rustacean way to achieve my goal?


回答1:


Since the condition is not very readable when put inside an if let / match block, I would just use a helper function to test for it:

impl Test {
    fn is_empty_a(&self) -> bool {
        if let Test::A(ref a) = *self {
            a.len() == 0
        } else {
            false
        }
    }
}

And then there shouldn't be any borrowing issues:

impl<'a> Iterator for Test {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        if self.is_empty_a() {
            *self = Test::B;
        }
        None
    }
}


来源:https://stackoverflow.com/questions/44899992/change-selector-in-match-when-selector-is-a-mutable-reference

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!