问题
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