Drain

接下来我们来看 Drain。Drain 在很大程度上和 IntoIter 相同,除了它不是消耗 Vec,而是借用 Vec 并保持其内存分配不变。现在我们只实现“基本”的全范围版本。

use std::marker::PhantomData; struct Drain<'a, T: 'a> { // Need to bound the lifetime here, so we do it with `&'a mut Vec<T>` // because that's semantically what we contain. We're "just" calling // `pop()` and `remove(0)`. vec: PhantomData<&'a mut Vec<T>>, start: *const T, end: *const T, } impl<'a, T> Iterator for Drain<'a, T> { type Item = T; fn next(&mut self) -> Option<T> { if self.start == self.end { None

-- 等等,这看起来很熟悉。让我们进行更多的压缩。IntoIter 和 Drain 具有完全相同的结构,让我们把它提取出来。

struct RawValIter<T> { start: *const T, end: *const T, } impl<T> RawValIter<T> { // unsafe to construct because it has no associated lifetimes. // This is necessary to store a RawValIter in the same struct as // its actual allocation. OK since it's a private implementation // detail. unsafe fn new(slice: &[T]) -> Self { RawValIter { start: slice.as_ptr(), end: if slice.len() == 0 { // if `len = 0`, then this is not actually allocated memory. // Need to avoid offsetting because that will give wrong // information to LLVM via GEP. slice.as_ptr() } else { slice.as_ptr().add(slice.len()) } } } } // Iterator and DoubleEndedIterator impls identical to IntoIter.

IntoIter 就变成了下面这样

pub struct IntoIter<T> { _buf: RawVec<T>, // we don't actually care about this. Just need it to live. iter: RawValIter<T>, } impl<T> Iterator for IntoIter<T> { type Item = T; fn next(&mut self) -> Option<T> { self.iter.next() } fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } } impl<T> DoubleEndedIterator for IntoIter<T> { fn next_back(&mut self) -> Option<T> { self.iter.next_back() } } impl<T> Drop for IntoIter<T> { fn drop(&mut self) { for _ in &mut *self {} } } impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(self) -> IntoIter<T> { unsafe { let iter = RawValIter::new(&self); let buf = ptr::read(&self.buf); mem::forget(self); IntoIter { iter, _buf: buf, } } } }

请注意,我在此设计中留下了一些怪癖,以便更容易地将 Drain 升级为使用任意子范围。特别是,我们可以让 RawValIter 在 drop 时自行 drain,但这对于更复杂的 Drain 来说是行不通的。我们还使用切片来简化 Drain 的初始化。

好了,现在 Drain 就非常简单了

use std::marker::PhantomData; pub struct Drain<'a, T: 'a> { vec: PhantomData<&'a mut Vec<T>>, iter: RawValIter<T>, } impl<'a, T> Iterator for Drain<'a, T> { type Item = T; fn next(&mut self) -> Option<T> { self.iter.next() } fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } } impl<'a, T> DoubleEndedIterator for Drain<'a, T> { fn next_back(&mut self) -> Option<T> { self.iter.next_back() } } impl<'a, T> Drop for Drain<'a, T> { fn drop(&mut self) { for _ in &mut *self {} } } impl<T> Vec<T> { pub fn drain(&mut self) -> Drain<T> { let iter = unsafe { RawValIter::new(&self) }; // this is a mem::forget safety thing. If Drain is forgotten, we just // leak the whole Vec's contents. Also we need to do this *eventually* // anyway, so why not do it now? self.len = 0; Drain { iter, vec: PhantomData, } } }

有关 mem::forget 问题的更多详细信息,请参阅关于泄漏的部分