如果我有一个本地的,可变的向量,我可以按照以下方式对其进行分区,从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?,我写了以下内容,它编译并将正确的值放入even
和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);
}
但是,即使我使用into_iter()
,这也不会消耗原始矢量。有一些关于可变性,借用或迭代器的东西,我只是没有到达这里。
答案 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);
}
答案 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);
}