Change selector to match if selector is a mutable reference

I want to change the enum variant based on some properties of the current enumeration variant in Iterator::next

. I have two attempts, none 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 works if I don't work with links 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 the selector changes? but the suggested solution is not general: it only works if the same function is executed in both branches.

What is Rustias' way to achieve my goal?

+3


source to share


1 answer


Since the condition is not very readable when inserted into a if let

/ block match

, I would just use a helper function to check:

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

      



And then there should be no problem with borrowing:

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

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

      

+3


source







All Articles