3

If I have a local, mutable vector, I can partition it as follows, copied from the documentation of partition.

let mut a = vec![1, 2, 3, 4];
let (even, odd): (Vec<i32>, Vec<i32>) = a.into_iter().partition(|&n| n % 2 == 0);

The a vector is consumed (moved) in this process. However, the same call to partition doesn't work if I have a borrowed mutable reference. If I try to use the same code in that case, I get the error:

error[E0277]: the trait bound `std::vec::Vec<i32>: std::iter::Extend<&mut i32>` is not satisfied
 --> src/main.rs:2:59
  |
2 |     let (even, odd): (Vec<i32>, Vec<i32>) = a.into_iter().partition(|n| **n % 2 == 0);
  |                                                           ^^^^^^^^^ the trait `std::iter::Extend<&mut i32>` is not implemented for `std::vec::Vec<i32>`
  |
  = help: the following implementations were found:
            <std::vec::Vec<T> as std::iter::Extend<&'a T>>
            <std::vec::Vec<T> as std::iter::Extend<T>>

Based on How to make a Rust mutable reference immutable?, I wrote the following, which compiles and puts the right values into even and odd.

fn doit(a: &mut Vec<i32>) {
    let (even, odd): (Vec<i32>, Vec<i32>) = (&*a).into_iter().partition(|&n| n % 2 == 0);
    println!("even {:?}, odd {:?}, a {:?}", even, odd, a);
}

However, this does not consume the original vector, even though I'm using into_iter(). There's something about mutability, borrowing, or iterators that I'm just not getting here.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mr. Kevin
  • 151
  • 5
  • *this does not consume the original vector* — you **cannot** consume something you don't own. That's just fundamental Rust. Why do you *want* to? – Shepmaster Feb 28 '18 at 01:58
  • Probably a duplicate of [How can I swap in a new value for a field in a mutable reference to a structure?](https://stackoverflow.com/q/27098694/155423) – Shepmaster Feb 28 '18 at 02:10
  • @Shepmaster What I really want is for retain() to return a vector of the removed elements, but partition() was the closest thing I found, so I figured I could re-populate the mutable vector after the call to partition. It's possible that I'm using the wrong tool for the job, and I should just iterate with a for loop and use swap_remove_back. (My actual code is using VecDeque) – Mr. Kevin Feb 28 '18 at 23:52
  • Do think that this is a duplicate of [Is there a way to drain parts of a vector based on a predicate?](https://stackoverflow.com/q/46651354/155423) then? Seems like it to me. – Shepmaster Mar 01 '18 at 02:11
  • It's close, but this question is more about how into_iter interacts with borrowing, and neither of the answers there have the workaround that @Jmb provides below. – Mr. Kevin Mar 02 '18 at 01:32
  • *and neither of the answers* — because it's in the **question** already. – Shepmaster Mar 02 '18 at 01:38

2 Answers2

4

As others have implied, you can't move the original vector since you don't own it. However you can move all the values out of the vector, leaving it empty. This can be accomplished with the drain method:

fn doit(a: &mut Vec<i32>) {
    let (even, odd): (Vec<i32>, Vec<i32>) = a.drain(..).partition(|&n| n % 2 == 0);
    println!("even {:?}, odd {:?}, a {:?}", even, odd, a);
}

playground

Jmb
  • 18,893
  • 2
  • 28
  • 55
1

The reason is that the IntoIterator trait is implemented differently for &'a mut Vec<T> and &'a Vec<T> then it is for Vec<T>. The First two create an iterator by value where as the Vec<T> version creates a consuming iterator, that is, one that moves each value out of the vector (from start to end). The vector cannot be used after calling into_iter(). So you can think of the first two &'a mut Vec<T> and &'a Vec<T> as using the values inside the reference to the Vector to create an iterator. Where as the Vec<T> you can think of it removing the values out of the Vec<T> and putting them into the iterator. Shepmaster's comment of not being able to consume something that you don't own is the reason why they are implemented differently.

Also be aware that there is different ways to get an iterator. From the Rust documentation:

  • iter(), which iterates over &T.
  • iter_mut(), which iterates over &mut T.
  • into_iter(), which iterates over T.

So you could also keep the function the same without doing (&*a) by using iter() instead of into_iter().

fn doit(a: &mut Vec<i32>) {
    let (even, odd): (Vec<i32>, Vec<i32>) = a.iter().partition(|&n| n % 2 == 0);
    println!("even {:?}, odd {:?}, a {:?}", even, odd, a);
}
Daniel Wilkins
  • 447
  • 4
  • 7