如何将切片添加到 Vec [英] How to prepend a slice to a Vec

查看:51
本文介绍了如何将切片添加到 Vec的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I was expecting a Vec::insert_slice(index, slice) method — a solution for strings (String::insert_str()) does exist.

我知道 Vec::insert(),但一次只插入一个元素,而不是切片.或者,当前置切片是 Vec 时,可以改为附加到它,但这不能概括.惯用的解决方案可能使用 Vec::splice(),但是在示例中使用迭代器让我摸不着头脑.

I know about Vec::insert(), but that inserts only one element at a time, not a slice. Alternatively, when the prepended slice is a Vec one can append to it instead, but this does not generalize. The idiomatic solution probably uses Vec::splice(), but using iterators as in the example makes me scratch my head.

其次,前面的整个概念似乎已从 docs 中剔除.一个都没有提到.我将不胜感激有关原因的评论.请注意,相对晦涩的方法,例如 Vec::swap_remove() 确实存在.

Secondly, the whole concept of prepending has seemingly been exorcised from the docs. There isn't a single mention. I would appreciate comments as to why. Note that relatively obscure methods like Vec::swap_remove() do exist.

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

My typical use case consists of indexed byte strings.

推荐答案

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

String::insert_str makes use of the fact that a string is essentially a Vec<u8>. It reallocates the underlying buffer, moves all the initial bytes to the end, then adds the new bytes to the beginning.

这通常不安全,不能直接添加到 Vec 中,因为在复制过程中 Vec 不再处于有效状态——其中存在漏洞"数据.

This is not generally safe and can not be directly added to Vec because during the copy the Vec is no longer in a valid state — there are "holes" in the data.

这对 String 没有影响,因为数据是 u8u8 没有实现 Drop.对于 Vec 中的任意 T 没有这样的保证,但是如果你非常小心地跟踪你的状态并正确清理,你可以做同样的事情——这是splice 做了什么!

This doesn't matter for String because the data is u8 and u8 doesn't implement Drop. There's no such guarantee for an arbitrary T in a Vec, but if you are very careful to track your state and clean up properly, you can do the same thing — this is what splice does!

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

the whole concept of prepending has seemingly been exorcised

我认为这是因为从性能的角度来看,添加到 Vec 是一个糟糕的主意.如果你需要这样做,天真的情况很简单:

I'd suppose this is because prepending to a Vec is a poor idea from a performance standpoint. If you need to do it, the naïve case is straight-forward:

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

这会占用更高的内存,因为我们需要有足够的空间来存放 v 的两个副本.

This has a bit higher memory usage as we need to have enough space for two copies of v.

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

The splice method accepts an iterator of new values and a range of values to replace. In this case, we don't want to replace anything, so we give an empty range of the index we want to insert at. We also need to convert the slice into an iterator of the appropriate type:

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

v.splice(0..0, s.iter().cloned());

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

splice's implementation is non-trivial, but it efficiently does the tracking we need. After removing a chunk of values, it then reuses that chunk of memory for the new values. It also moves the tail of the vector around (maybe a few times, depending on the input iterator). The Drop implementation of Slice ensures that things will always be in a valid state.

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

I'm more surprised that VecDeque doesn't support it, as it's designed to be more efficient about modifying both the head and tail of the data.

这篇关于如何将切片添加到 Vec的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆