gpt4 book ai didi

rust - 当长度不变时, Vec::splice() 是否有效?

转载 作者:行者123 更新时间:2023-12-03 11:24:32 60 4
gpt4 key购买 nike

当您使用 Vec::splice() 替换 Vec 的一部分,是否足够聪明地专门处理替换与它正在替换的 block 长度相同的情况,还是我应该自己处理?
这样做有什么意义,或者是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);
}
}

最佳答案

我屈服并阅读了代码。处理这种情况足够聪明。以下是代码的工作原理:

  • 您调用.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() }
    }
  • Splice被丢弃,它调用它的 drop()执行。
    impl<I: Iterator> Drop for Splice<'_, I> {
    fn drop(&mut self) {
    它做的第一件事就是删除所有被替换的元素。
            self.drain.by_ref().for_each(drop);
    然后它检查替换是否在 Vec 的末尾。 ,如果是这样,只需扩展它并返回。
            unsafe {
    if self.drain.tail_len == 0 {
    self.drain.vec.as_mut().extend(self.replace_with.by_ref());
    return;
    }
    接下来它调用一个助手 fill()函数,用替换迭代器(replace_with)中尽可能多的元素替换已删除的元素。 fill()返回 false如果它没有填满整个替换范围,在这种情况下它会返回(我不确定在这种情况下尾部移动到哪里了?)
                // First fill the range left by drain().
    if !self.drain.fill(&mut self.replace_with) {
    return;
    }
    现在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;
    }
    }
    您可能期望 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);
    }
    关键是如果 replace_with是空的,因为替换大小与范围相同,那么所有这些操作都是相当简单的 nop-ish 事情。
    最后一位删除Drain迭代器本身,它将移动尾部..可能再次?我不知道我在这里迷路了。无论如何,如果长度相同,它肯定不会移动它。
            }
    // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
    }
    }
  • 关于rust - 当长度不变时, Vec::splice() 是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62557790/

    60 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com