插入和删除

slice 不提供的东西是“insert”和“remove”,所以我们接下来做这些。

insert 需要将目标索引的所有元素向右移动一个。要做到这一点,我们需要使用ptr::copy,它是 C 语言memmove的 Rust 版本。它将一些内存块从一个位置复制到另一个位置,正确处理源和目标重叠的情况(这在这里肯定会发生)。

如果我们在索引i处插入,我们要使用旧的 len 将[i ... len]转移到[i+1 ... len+1]

  1. pub fn insert(&mut self, index: usize, elem: T) {
  2. // 注意:`<=` 是因为我们可以把值插入到任何索引范围 ([0,length-1]) 内的位置之后
  3. // 这种情况等同于 push
  4. assert!(index <= self.len, "index out of bounds");
  5. if self.cap == self.len { self.grow(); }
  6. unsafe {
  7. // ptr::copy(src, dest, len) 的含义: "从 dst 复制连续的 len 个元素到 src "
  8. ptr::copy(self.ptr.as_ptr().add(index),
  9. self.ptr.as_ptr().add(index + 1),
  10. self.len - index);
  11. ptr::write(self.ptr.as_ptr().add(index), elem);
  12. self.len += 1;
  13. }
  14. }

remove 的行为方式正好相反。我们需要将所有的元素从[i+1 ... len + 1]转移到[i ... len],使用新的 len。

  1. pub fn remove(&mut self, index: usize) -> T {
  2. // 注意:使用 `<` 是因为 index 不能删除超出元素下标的范围
  3. assert!(index < self.len, "index out of bounds");
  4. unsafe {
  5. self.len -= 1;
  6. let result = ptr::read(self.ptr.as_ptr().add(index));
  7. ptr::copy(self.ptr.as_ptr().add(index + 1),
  8. self.ptr.as_ptr().add(index),
  9. self.len - index);
  10. result
  11. }
  12. }