有没有一种方法可以优雅地解决“在可变引用后面移动”而不实现“复制”特征?

mte*_*eXD 0 mergesort rust borrow-checker

我正在尝试在 Rust 中实现合并排序的合并功能。问题是我试图为泛型类型执行此操作T,该类型仅受std::cmp::PartialOrd.

这是代码:

fn my_merge<T: std::cmp::PartialOrd>(a: &mut Vec<T>, mut b: &mut Vec<T>) -> Vec<T> {
    let mut res: Vec<T> = Vec::new();
    let mut a_iter = a.into_iter();  //  !!!
    let mut b_iter = b.into_iter();  //  !!!

    while let (Some(a_item), Some(b_iter)) = (a_iter.next(), b_iter.next()) {
        if a_item <= b_item {
            res.push(*a_item);  // !!!
        } else {
            res.push(*b_item);  // !!!
        }        
    }

    // ... Omitted code ...

    res
}
Run Code Online (Sandbox Code Playgroud)

在查看文档时,我发现了该into_iter()方法,该next()方法应该产生T而不是&T. 但只有当迭代器不是在引用上构造时,它才会这样做(因为我将切片传递到函数中)。(快速提醒:这是因为借用的工作方式。请参阅此 StackOverflow 问题

这与不能取消引用变量a_itemb_item带注释的行的原因相同。

我的问题是:有没有办法在保持泛型类型的同时解决这个问题?这几乎是自相矛盾的,因为理论上这是一项非常简单的任务 - “只需将元素的所有权从一个向量移动到另一个向量” - 但由于所有权规则,这并不那么简单。

kmd*_*eko 6

您可以使用以下方法迭代一段Vec时间,声明元素的所有权,而无需消耗原始元素本身:Vec.drain(..)

fn my_merge<T: std::cmp::PartialOrd>(a: &mut Vec<T>, b: &mut Vec<T>) -> Vec<T> {
    let mut res: Vec<T> = Vec::new();
    let mut a_iter = a.drain(..);
    let mut b_iter = b.drain(..);

    while let (Some(a_item), Some(b_item)) = (a_iter.next(), b_iter.next()) {
        if a_item <= b_item {
            res.push(a_item);
        } else {
            res.push(b_item);
        }        
    }

    res
}
Run Code Online (Sandbox Code Playgroud)

这当然会使输入 (ab) 为空,但在合并后仍保留其原始容量。