rust - 如何在Vec上更新或插入?

Posted 跨链技术践行者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rust - 如何在Vec上更新或插入?相关的知识,希望对你有一定的参考价值。

我正在用Rust编写数据结构。它包含键值对的Vec。当插入结构时,我需要找到一个匹配的键并同时更新键和值(实际上是一个子指针)。代码看起来像这样,其中pivotsref mutVec<Pivot>,而Pivot只是具有两个字段的结构:

match pivots.iter_mut().find(|ref p| key <= p.min_key) { // first mutable borrow
    Some(ref mut pivot) => {
        // If there is one, insert into it and update the pivot key
        pivot.min_key = key;
        pivot.child.insert(key, value) // recursive call
    },
    // o/w, insert a new leaf at the end
    None => pivots.push(Pivot /* ... */) // second mutable borrow
}


但是有一个问题。即使我没有在match的第二个分支中使用可变的迭代器,借阅检查器仍提示我“一次不能借用*pivots可变为多次”。

这对我来说很有意义,因为即使在match的情况下不使用第一个借位,它仍然在范围内。这有点不方便:聪明的检查员当然可以说这些借贷是不重叠的。我见过有人在网上建议使用早退以避免这种问题,例如:

match pivots.iter_mut().find(|ref p| key <= p.min_key) {
    Some(ref mut pivot) => {
        pivot.min_key = key;
        pivot.child.insert(key, value);
        return
    },
    None => ()
};
pivots.push(Pivot /* ... */)


但这似乎很难理解,尤其是当它意味着将此代码分解为自己的函数以允许return时。有没有更惯用的方式来执行更新或插入操作?

最佳答案

从长远来看,有一个合并的RFC "non-lexical lifetimes"可以解决这个问题。使用Rust 1.31中可用的Rust 2018中的非词汇生存期,您的代码将按原样运行:

Playground

use std::collections::HashMap;

pub struct Pivot {
    pub min_key: u64,
    pub child: HashMap<u64, ()>,
}

fn update_or_append(pivots: &mut Vec<Pivot>, key: u64, value: ()) {
    match pivots.iter_mut().find(|ref p| key <= p.min_key) {
        Some(pivot) => {
            // If there is one, insert into it and update the pivot key
            pivot.min_key = key;
            pivot.child.insert(key, value);
            return;
        }
        // o/w insert a new leaf at the end
        None => {
            let mut m = HashMap::new();
            m.insert(key, value);
            pivots.push(Pivot {
                min_key: key,
                child: m,
            });
        }
    }
}

fn main() {
    let mut pivots = Vec::new();
    update_or_append(&mut pivots, 100, ());
}


如果此不适用于您的代码,请 checkout

  • Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?


     
  • 在Rust 2018之前,您可以通过一些其他控制流处理来解决它。

    无论更新是否发生,您都可以让您的匹配产生一个bool值,并在下面使用该值附加条件块。我考虑将“update-or-append”逻辑放入单独的函数中(在更新后使用return)是更惯用的方法:

    Playground
    use std::collections::HashMap;
    
    pub struct Pivot {
        pub min_key: u64,
        pub child: HashMap<u64, ()>,
    }
    
    fn update_or_append(pivots: &mut Vec<Pivot>, key: u64, value: ()) {
        if let Some(pivot) = pivots.iter_mut().find(|ref p| key <= p.min_key) {
            // If there is one, insert into it and update the pivot key
            pivot.min_key = key;
            pivot.child.insert(key, value);
            return;
        }
        // otherwise insert a new leaf at the end
        let mut m = HashMap::new();
        m.insert(key, value);
        pivots.push(Pivot {
            min_key: key,
            child: m,
        });
    }
    
    fn main() {
        let mut pivots = Vec::new();
        update_or_append(&mut pivots, 100, ());
    }
    

    使用bool跟踪更新是否发生:

    Playground
    use std::collections::HashMap;
    
    pub struct Pivot {
        pub min_key: u64,
        pub child: HashMap<u64, ()>,
    }
    
    fn update_or_append(pivots: &mut Vec<Pivot>, key: u64, value: ()) {
        let updated = match pivots.iter_mut().find(|ref p| key <= p.min_key) {
            Some(pivot) => {
                // If there is one, insert into it and update the pivot key
                pivot.min_key = key;
                pivot.child.insert(key, value);
                true
            }
            // o/w insert a new leaf at the end below
            None => false,
        };
        if !updated {
            let mut m = HashMap::new();
            m.insert(key, value);
            pivots.push(Pivot {
                min_key: key,
                child: m,
            });
        }
    }
    
    fn main() {
        let mut pivots = Vec::new();
        update_or_append(&mut pivots, 100, ());
    }
    

    关于rust - 如何在Vec上更新或插入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47395171/

以上是关于rust - 如何在Vec上更新或插入?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Rust中提高元素乘法的性能?

如何将 C 变长数组代码转换为 Rust?

如何将 Rust `Vec<T>` 暴露给 FFI?

Rust Diesel sql_query 带有返回的插入示例

迭代Rust Vec的首选方法?

如何在 Rust 中过滤自定义结构的向量?