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

问题描述 投票:0回答:2

如果我有一个本地的,可变的向量,我可以按如下方式对其进行分区,从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(),这也不会消耗原始矢量。有一些关于可变性,借用或迭代器的东西,我只是没有到达这里。

rust
2个回答
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
投票

原因是对于&'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);
}
© www.soinside.com 2019 - 2024. All rights reserved.