我想迭代一次数组/向量,并在此途中修改多个元素,因为这是最佳的解决方案。我不想一遍又一遍地扫描它,因为Rust对借贷不满意。
我存储了一个间隔列表,这些间隔表示为[start;stop]有序向量,并且我想添加一个新间隔。它可能是重叠的,所以我想删除不再需要的所有元素。我要一劳永逸。算法看起来像这样(我削减了一些部分):
[start;stop]
use std::cmp::{min, max}; #[derive(Debug, PartialEq, Clone, Copy)] struct Interval { start: usize, stop: usize, } impl Interval { fn new(start: usize, stop: usize) -> Interval { Interval { start: start, stop: stop, } } pub fn starts_before_disjoint(&self, other: &Interval) -> bool { self.start < other.start && self.stop < other.start } pub fn starts_before_non_disjoint(&self, other: &Interval) -> bool { self.start <= other.start && self.stop >= other.start } pub fn starts_after(&self, other: &Interval) -> bool { self.start > other.start } pub fn starts_after_disjoint(&self, other: &Interval) -> bool { self.start > other.stop } pub fn starts_after_nondisjoint(&self, other: &Interval) -> bool { self.start > other.start && self.start <= other.stop } pub fn disjoint(&self, other: &Interval) -> bool { self.starts_before_disjoint(other) } pub fn adjacent(&self, other: &Interval) -> bool { self.start == other.stop + 1 || self.stop == other.start - 1 } pub fn union(&self, other: &Interval) -> Interval { Interval::new(min(self.start, other.start), max(self.stop, other.stop)) } pub fn intersection(&self, other: &Interval) -> Interval { Interval::new(max(self.start, other.start), min(self.stop, other.stop)) } } fn main() { //making vectors let mut vec = vec![ Interval::new(1, 1), Interval::new(2, 3), Interval::new(6, 7), ]; let addition = Interval::new(2, 5); // <- this will take over interval @ 2 and will be adjacent to 3, so we have to merge let (mut i, len) = (0, vec.len()); while i < len { let r = &mut vec[i]; if *r == addition { return; //nothing to do, just a duplicate } if addition.adjacent(r) || !addition.disjoint(r) { //if they are next to each other or overlapping //lets merge let mut bigger = addition.union(r); *r = bigger; //now lets check what else we can merge while i < len - 1 { i += 1; let next = &vec[i + 1]; if !bigger.adjacent(next) && bigger.disjoint(next) { //nothing to merge break; } vec.remove(i); //<- FAIL another mutable borrow i -= 1; //lets go back vec[i] = bigger.union(next); //<- FAIL and yet another borrow } return; } if addition.starts_before_disjoint(r) { vec.insert(i - 1, addition); // <- FAIL since another refence already borrowed @ let r = &mut vec[i] } i += 1; } }
由于借款规则,它在几个地方失败了。有没有办法
有借用拆分功能,但我看不到如何在这里应用。
通常,您 不能这样做, 因为这 正是Rust可以防止的一类错误。请检查此事件序列,在该序列中我已i用唯一变量替换,因为编译器仍然不知道将使用什么值。
i
let r = &mut vec[i1]; let next = &vec[i2]; vec.remove(i3); vec[i4] = bigger.union(next); vec.insert(i5, addition);
i1
i2
vec.remove(i3)
next
r
i5
i4
请注意,它们分别对应于编译器告诉您的要点。
这 可能 是 一些 这些案件可能是通过非词汇的寿命是固定的,如果编译器变得足够聪明地理解您不再需要有围绕基准。在通过数组索引更改向量的情况下将无济于事;编译器不够聪明,无法跟踪数学并证明您从未碰过“错误”的索引,如果索引是索引,则编译器也不够聪明,无法意识到数组中的两个引用是不相交的。
在 这种情况下 ,由于您的类型实现了Copy,请利用该类型来获取值。必要时直接写回向量。 如果您从不借贷, 就不会有借贷错误。
Copy
fn main() { let mut vec = vec![ Interval::new(1, 1), Interval::new(2, 3), Interval::new(6, 7), ]; let addition = Interval::new(2, 5); let (mut i, len) = (0, vec.len()); while i < len { let r = vec[i]; if r == addition { return; } if addition.adjacent(&r) || !addition.disjoint(&r) { let mut bigger = addition.union(&r); vec[i] = bigger; while i < len - 1 { i += 1; let next = vec[i + 1]; if !bigger.adjacent(&next) && bigger.disjoint(&next) { break; } vec.remove(i); i -= 1; vec[i] = bigger.union(&next); } return; } if addition.starts_before_disjoint(&r) { vec.insert(i - 1, addition); } i += 1; } }
实际上,我会按照loganfsmyth的建议进行操作,并将算法更改为采用一片间隔并返回新的Vec。如果您经常这样做,则可以在两个预分配的Vecs之间来回翻转写入,但是到那时,数据结构可能比向量要好得多。也许是一棵间隔树。
Vec