rust - 如何在Vec上更新或插入?
Posted 跨链技术践行者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rust - 如何在Vec上更新或插入?相关的知识,希望对你有一定的参考价值。
我正在用Rust编写数据结构。它包含键值对的Vec
。当插入结构时,我需要找到一个匹配的键并同时更新键和值(实际上是一个子指针)。代码看起来像这样,其中pivots
是ref mut
的Vec<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
)是更惯用的方法:
Playgrounduse 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
跟踪更新是否发生:
Playgrounduse 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上更新或插入?的主要内容,如果未能解决你的问题,请参考以下文章