如何划分可变借入的向量?

时间:2018-02-28 01:53:42

标签: rust

如果我有一个本地的,可变的向量,我可以按照以下方式对其进行分区,从partition的文档中复制。

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

在此过程中消耗(移动)a向量。但是,如果我有一个借用的可变引用,那么对分区的同一调用也不起作用。如果我尝试在这种情况下使用相同的代码,我会收到错误:

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

基于How to make a Rust mutable reference immutable?,我写了以下内容,它编译并将正确的值放入evenodd

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);
}

但是,即使我使用into_iter(),这也不会消耗原始矢量。有一些关于可变性,借用或迭代器的东西,我只是没有到达这里。

2 个答案:

答案 0 :(得分:2)

正如其他人暗示的那样,你不能移动原始载体,因为你不拥有它。但是,您可以将所有值移出矢量,将其留空。这可以使用drain方法完成:

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

答案 1 :(得分:1)

原因是,对于&'a mut Vec<T>&'a Vec<T>,IntoIterator特征的实现方式不同,那么它是Vec<T>。前两个按值创建迭代器,其中Vec<T>版本创建一个消费迭代器,即将每个值移出向量(从开始到结束)的迭代器。调用into_iter()后无法使用向量。因此,您可以将前两个&'a mut Vec<T>&'a Vec<T>视为使用Vector引用中的值来创建迭代器。作为Vec<T>,您可以将其从Vec<T>中移除并将它们放入迭代器中。 Shepmaster的评论是不能消费你不拥有的东西,这是他们以不同方式实施的原因。

还要注意,有不同的方法来获取迭代器。 来自Rust文档:

  • iter(),它遍历&T
  • iter_mut(),它遍历&mut T
  • into_iter(),它遍历T

因此,您可以使用(&*a)代替iter()而不使用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);
}