手动带你实现vec,早日变大神

28 阅读2分钟

前面我们已经实现了一个基础的Vec了,也就是一个栈。我们可以push和pop,也可以自动清理回收,但只有这些还是远远不够的。特别是我们已经有了一个数组,但是没有slice相关的功能,那么有什么办法能实现slice了,这个也非常的容易就是实现Deref<Target=<T>>,这样我们的Vec神奇的可以编程了slice。我们只需要使用 slice::from_row_ports。它能够为我们正确的处理空slice,等到后面我们完成了零尺寸类型的支持,它们依然可以完美的配合。

实现Deref和DerefMut

use std::ops::Deref;

impl <T> Deref for Vec<T>{
  type Target = [T];
  fn deref(&self-> &[T]{
    unsafe {
      std::slice::from_raw_parts(self.ptr.as_ptr(), self.len)
    }
  }
}

5a7d949c7433932beb5448dd4bc21f17.jpg

顺便我们也把DerefMut一并实现了:

use std::ops:DerefMut;
impl <T> DerefMut for Vec<T> {
  fn deref_mut(&mut self->&mut [T]{
    unsafe{
      std::slice::from_row_parts_mut(self.ptr.as_ptr(),self.len);
    }
  }
}

到了这里,恭喜啊,现在我们有了len,first,last,索引分片排序iteriter_mut以及slice能提供所有的功能。

但是作为一个Vec怎么能没有插入和删除了,明显是不合理的,首先你得能往Vec中插入元素才能做排序,索引这些了,因此实现Vec的插入和删除也是很重要的,因此我们还是很有必要实现这两个很重要的方法。

实现插入和删除方法

a4dc17ff5cb62bf0728bf76e2c11627e.jpg

可惜的是slice并没有删除和插入功能,因此我们要实现它们。

首先是插入的基本思路和原理,插入就是把目标位置都向右移动一个位置,这里我们会用到ptr::copy,它能把一块内存拷贝到另一个地方,而且可以正确处理资源和目标内存区域有重叠的情况。如果我们在i这个位置插入一个元素,那么我们就需要把[i..len]移动到[i+1,len],len指的是插入钱的值。

pub insert (&mut self,index::uszie,elem:T){
  assert!(index <= self.len,"index out of bounds");
  if self.cap == self.len {
    self.grow();
  }
  unsafe {
    if index < self.len{
      // ptr::copy(src, dest, len): "从src拷贝len个元素到dest"
      ptr::copy(self.ptr.offset(index as isize),
                self.ptr.offset(index as isize +1),
                self.len -index);
    }
    ptr::write(self.offset(index as isize),elem);
    self.len += 1;
  }
}

删除则是完全相反的行为,我们只需要把元素[i+1 .. len+1]移动到[i..len]。len是删除后的值。

pub fn remove(&mut self,index:usize-> T{ 
  // 注意,<是因为我们不能删除所有元素之后的位置
  assert!(index < self.len,"index out of bounds");
  unsefe{
    self.len -= 1;
    let result = ptr::read(self.prt.offset(index as isize));
    ptr::copy(self.ptr.offset(index as isize + 1),
              self.ptr.offset(index as isize),
              self.len - index);
    result
  }
}

最后欢迎大家关注我的公众号:花说编程,是一个rust狂热爱好者和数据库内核工程师