如何在Vec之前添加切片

use*_*185 5 rust

我期待有一种Vec::insert_slice(index, slice)方法— String::insert_str()确实存在字符串()的解决方案。

我知道Vec::insert(),但是一次只插入一个元素,而不是切片。或者,当前置切片为一个切片时,Vec可以附加一个切片,但这不能一概而论。惯用的解决方案可能使用Vec::splice(),但如示例中那样使用迭代器会让我抓狂。

其次,似乎从文档中排除了前置的整个概念。没有任何提及。我会很感激关于原因的评论。注意,Vec::swap_remove()确实存在相对模糊的方法。

我的典型用例由索引字节字符串组成。

She*_*ter 7

String::insert_str利用字符串本质上是一个Vec<u8>. 它重新分配底层缓冲区,将所有初始字节移动到末尾,然后将新字节添加到开头

这通常是不安全的,不能直接添加,Vec因为在复制过程中Vec它不再处于有效状态——数据中有“漏洞”。

这无关紧要,String因为数据是u8u8不实现Drop. 有一个任意没有这样的保证TVec,但如果你是非常仔细地跟踪您的状态,并妥善清理,你可以做同样的事情-这是什么splice呢!

整个前置的概念似乎已被驱除

我想这是因为Vec从性能的角度来看,在 a 之前是一个糟糕的主意。如果你需要这样做,天真的情况很简单:

fn prepend<T>(v: Vec<T>, s: &[T]) -> Vec<T>
where
    T: Clone,
{
    let mut tmp: Vec<_> = s.to_owned();
    tmp.extend(v);
    tmp
}
Run Code Online (Sandbox Code Playgroud)

这具有更高的内存使用量,因为我们需要有足够的空间用于v.

splice方法接受新值的迭代器和要替换的值范围。在这种情况下,我们不想替换任何内容,因此我们给出了要插入的索引的空范围。我们还需要将切片转换为适当类型的迭代器:

let s = &[1, 2, 3];
let mut v = vec![4, 5];

v.splice(0..0, s.iter().cloned());
Run Code Online (Sandbox Code Playgroud)

splice的实现是不平凡的,但它有效地完成了我们需要的跟踪。删除一大块值后,它会为新值重用那块内存。它还会移动向量的尾部(可能会移动几次,具体取决于输入迭代器)。的Drop实现Slice确保事物始终处于有效状态。


我更惊讶的是VecDeque不支持它,因为它旨在更有效地修改数据的头部和尾部。