当您使用Vec::splice()
替换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);
}
}
3条答案
按热度按时间8i9zcol21#
我屈服了,读了代码。他很聪明,足以应付这种情况。代码的工作原理如下:
1.你调用
.splice()
,它会创建一个Splice
对象,其中包含一个Drain
迭代器用于替换范围:Splice
被丢弃,这将调用其drop()
实现。它做的第一件事是删除所有被替换的元素。
然后它检查替换是否在
Vec
的末尾,如果是,只需扩展它并返回。接下来,它调用一个辅助函数
fill()
,用替换迭代器(replace_with
)中尽可能多的元素替换被删除的元素。fill()
返回false
,如果它没有填满整个替换范围,在这种情况下它返回(我不确定在这种情况下尾部移动到哪里?)现在
replace_with
可能剩下0个元素(在这种情况下,我们完成了),或者它可能有更多的元素(在这种情况下,尾部需要向后移动该数量)。这就是接下来发生的事情。你可能期望
if lower_bound == 0 { return; }
,但lower_bound
只是一个估计值,所以它首先尝试,如果失败,它会将替换复制到一个临时向量中,这样它就可以知道完整的长度。关键是,如果
replace_with
* 是 * 空的,因为替换大小与范围相同,那么所有这些操作都是相当简单的nop-ish事情。最后一位删除
Drain
迭代器本身,这将移动尾部。可能再次?我不知道我有点忘了。不管怎样,如果长度是一样的,它肯定不会移动它。tktrz96b2#
根据文档和another answer,
splice
在少数情况下是“智能”(最佳)的,包括“[replace_with
]的size_hint()
的下限是精确的”的情况。在示例函数中,
replacement.iter()
上的size_hint()
的下限是精确的,因此应该执行一次内存移动。fafcakar3#
据我所知,
Splice::drop
是完成大部分工作的,它调用fill
,在匹配长度的情况下,它将通过replace_with
进行重定向,并返回true
,但将replace_with
留空,因此lower_bound
为0,collected.len()
为0。Drain::drop
然后运行。循环应该什么都不做,因为Splice::drop
已经迭代过了,然后DropGuard::drop
,可能需要移动元素,不应该需要移动/复制元素,因为作为长度匹配的结果,tail
应该等于start
。