如何在没有“自我”的方法中对Vec进行分区?

时间:2014-12-16 06:09:41

标签: rust

所以,有一些结构看起来像这样:

struct foo {
    alpha: Vec<T>,
    beta: Vec<T>,
}

并且某些方法应该移动一些与alphabeta的某些条件匹配的值。问题是:如果不拥有self,干净的方式是什么?

无法使用Vec::partition()方法,因为self.alpha的任何移动都会导致cannot move out of dereference of &mut-pointer编译错误。

PS:T里面有File,所以它没有实现Clone

1 个答案:

答案 0 :(得分:3)

你想放弃beta吗?这是std::mem::replace的用途,允许你把它拉出来:

use std::mem;

impl Foo {
    fn munge(&mut self) {
        let alpha = mem::replace(&mut self.alpha, Vec::new());
        let (alpha, beta) = alpha.partition(…);
        self.alpha = alpha;
        self.beta = beta;
    }
}

请注意, 是在那里短暂创建的新Vec,但这并不重要;它不涉及分配,而且非常便宜。 (另一种方法是在那里留下未初始化的内存并再次替换它,忘记未初始化的内存,但如果分区失败则不安全,因为它将在未初始化的内存上运行析构函数。)


由于您只想移动与谓词匹配的元素,因此值得研究partition的实现方式:

pub fn partition<F>(self, mut f: F) -> (Vec<T>, Vec<T>) where F: FnMut(&T) -> bool {
    let mut lefts  = Vec::new();
    let mut rights = Vec::new();

    for elt in self.into_iter() {
        if f(&elt) {
            lefts.push(elt);
        } else {
            rights.push(elt);
        }
    }

    (lefts, rights)
}

知道这是它的实现方式使得实现类似于不涉及创建第二个向量的东西是相当容易的;这是一般的想法:

let source = mem::replace(&mut self.alpha, Vec::new());
for element in source.into_iter() {
    if f(&element) { /* for some `f` */
        self.alpha.push(element)
    } else {
        self.beta.push(element)
    }
}

真的,mem::replace是你需要知道的关于这些事情的唯一事情;其余的变得相当容易。