Iterator :: unzip中SizeHint的目的是什么?

qed*_*qed 7 rust

从Rust标准库的实现unzip:

fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB) where
    FromA: Default + Extend<A>,
    FromB: Default + Extend<B>,
    Self: Sized + Iterator<Item=(A, B)>,
{
    struct SizeHint<A>(usize, Option<usize>, marker::PhantomData<A>);
    impl<A> Iterator for SizeHint<A> {
        type Item = A;

        fn next(&mut self) -> Option<A> { None }
        fn size_hint(&self) -> (usize, Option<usize>) {
            (self.0, self.1)
        }
    }

    let (lo, hi) = self.size_hint();
    let mut ts: FromA = Default::default();
    let mut us: FromB = Default::default();

    ts.extend(SizeHint(lo, hi, marker::PhantomData));
    us.extend(SizeHint(lo, hi, marker::PhantomData));

    for (t, u) in self {
        ts.extend(Some(t));
        us.extend(Some(u));
    }

    (ts, us)
}
Run Code Online (Sandbox Code Playgroud)

这两行:

ts.extend(SizeHint(lo, hi, marker::PhantomData));
us.extend(SizeHint(lo, hi, marker::PhantomData));
Run Code Online (Sandbox Code Playgroud)

实际上并没有扩展tsus任何东西,因为返回的next方法.这样做的目的是什么?SizeHintNone

mal*_*rbo 5

这是一个很酷的技巧.通过给这个尺寸暗示,它提供了tsus预留空间,为有机会extend在循环调用.根据documentation

size_hint()主要用于优化,例如为迭代器的元素保留空间,但不能信任,例如省略不安全代码中的边界检查.不正确的实施size_hint()不应导致内存安全违规.

请注意,创建SizeHint是必要的,因为extendfor循环中的调用是使用Some值(Optional实现Iterator特征),而size_hintfor Some(1, Some(1)).这对预分配没有帮助.

但是查看代码Vec,这将没有任何影响(无论是在HashMapVecDeque).其他Extend实现可能不同.

执行ts.extend(SizeHint(lo, hi, marker::PhantomData));不会触发a resize,因为next返回None.也许有人应该写一个补丁.

impl<T> Vec<T> {
    fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
        // This function should be the moral equivalent of:
        //
        //      for item in iterator {
        //          self.push(item);
        //      }
        while let Some(element) = iterator.next() {
            let len = self.len();
            if len == self.capacity() {
                let (lower, _) = iterator.size_hint();
                self.reserve(lower.saturating_add(1));
            }
            unsafe {
                ptr::write(self.get_unchecked_mut(len), element);
                // NB can't overflow since we would have had to alloc the address space
                self.set_len(len + 1);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


blu*_*uss 5

这是一个可疑的黑客!

它实现了一个带有虚假(高估)大小提示的迭代器,以鼓励生成的集合预先保留最终合适的容量。

很酷的技巧,但是,它通过实现一个大小提示来实现,其中估计的下限大于生成的实际元素数 (0)。如果下限未知,迭代器应该返回一个下限 0。由于这个原因,这个实现可以说是非常有问题的,并且集合的 Extend impl 可能会因此产生错误(但当然不是内存不安全。)