My code looks like this:
struct Bar {
i: i32,
}
struct Foo {
v: Vec<Bar>,
}
impl Foo {
fn foo(&mut self) {
self.v.drain(self.v.iter().filter(|b| b.i < 10));
}
}
Note that Bar
is not allowed to be copied or cloned.
I want to delete all Bar
s that don't satisfy that condition. Initially I thought I could just iterate over them and call remove
but I am not allowed to have two mutable borrows or one mutable borrow if there is an immutable borrow which makes total sense.
I guess the easiest thing would be to just clone
, filter
and collect
, but I am not allowed to clone or copy.
How would I do this?
If you look at the interface of Vec
, you will not find a method that erases some elements based on a predicate. Instead you will find retain
which keeps the elements based on a predicate.
Of course, both are symmetric, it's just that retain
is harder to find if you filter method names by "remove" or "erase" (it does contain "remove" in its description).
The example provided speaks for itself:
let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
In nightly Rust, you can use Vec::drain_filter
:
#![feature(drain_filter)]
#[derive(Debug)]
struct Bar {
i: i32,
}
fn main() {
let mut bars = vec![Bar { i: 1 }, Bar { i: 10 }, Bar { i: 3 }, Bar { i: 100 }];
bars.drain_filter(|b| b.i < 10);
println!("{:?}", bars);
}
What's extra interesting about drain_filter
is that you can get the rejected values as it returns an iterator of them:
let rejects: Vec<_> = bars.drain_filter(|b| b.i < 10).collect();
You can also choose to modify the value being iterated over:
bars.drain_filter(|b| {
b.i -= 1;
b.i < 10
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With