当你Vec::splice()用来替换 a 的一部分时Vec,它是否足够聪明来专门处理替换与它正在替换的块长度相同的情况,还是我应该自己处理?
这样做有什么意义,还是array.splice()足够聪明来这样做?
fn example(array: Vec<u64>, replacement: Vec<u64>, range: std::ops::Range<usize>) {
if (replacement.len() == range.len()) {
for i in range {
array[i] = replacement[i];
}
} else {
array.splice(range, replacement);
}
}
Run Code Online (Sandbox Code Playgroud)
我屈服并阅读了代码。它是足够聪明来处理这种情况。下面是代码的工作原理:
您调用.splice(),它会创建一个Splice包含Drain替换范围迭代器的对象:
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
where
R: RangeBounds<usize>,
I: IntoIterator<Item = T>,
{
Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
}
Run Code Online (Sandbox Code Playgroud)
将Splice被丢弃,这就要求其drop()实施。
impl<I: Iterator> Drop for Splice<'_, I> {
fn drop(&mut self) {
Run Code Online (Sandbox Code Playgroud)
它做的第一件事是删除所有被替换的元素。
self.drain.by_ref().for_each(drop);
Run Code Online (Sandbox Code Playgroud)
然后它检查替换是否在 的末尾Vec,如果是,则扩展它并返回。
unsafe {
if self.drain.tail_len == 0 {
self.drain.vec.as_mut().extend(self.replace_with.by_ref());
return;
}
Run Code Online (Sandbox Code Playgroud)
接下来它调用一个辅助fill()函数,用替换迭代器 ( replace_with) 中尽可能多的元素替换已删除的元素。fill()回报false,如果它没有填满整个替换范围的,在这种情况下,它返回(我不知道在哪里,尾巴在这种情况下,虽然感动?)
// First fill the range left by drain().
if !self.drain.fill(&mut self.replace_with) {
return;
}
Run Code Online (Sandbox Code Playgroud)
现在replace_with可能剩下 0 个元素(在这种情况下我们完成了),或者它可能有更多元素(在这种情况下尾部需要向后移动那个数量)。这就是接下来发生的事情。
// There may be more elements. Use the lower bound as an estimate.
// FIXME: Is the upper bound a better guess? Or something else?
let (lower_bound, _upper_bound) = self.replace_with.size_hint();
if lower_bound > 0 {
self.drain.move_tail(lower_bound);
if !self.drain.fill(&mut self.replace_with) {
return;
}
}
Run Code Online (Sandbox Code Playgroud)
您可能会期望if lower_bound == 0 { return; },但这lower_bound只是一个估计值,因此它首先尝试使用它,如果失败,它将替换复制到一个临时向量中,因此它可以知道全长。
// Collect any remaining elements.
// This is a zero-length vector which does not allocate if `lower_bound` was exact.
let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
// Now we have an exact count.
if collected.len() > 0 {
self.drain.move_tail(collected.len());
let filled = self.drain.fill(&mut collected);
debug_assert!(filled);
debug_assert_eq!(collected.len(), 0);
}
Run Code Online (Sandbox Code Playgroud)
关键是如果replace_with 为空,因为替换大小与范围相同,那么所有这些操作都是相当简单的nop-ish。
最后一位删除Drain迭代器本身,这将移动尾部......可能再次?我不知道我在这里迷失了方向。无论如何,如果长度相同,它肯定不会移动它。
}
// Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
270 次 |
| 最近记录: |