首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SizeHint在Iterator::unzip中的用途是什么?

SizeHint在Iterator::unzip中的用途是什么?
EN

Stack Overflow用户
提问于 2016-05-06 14:13:32
回答 2查看 1.5K关注 0票数 8

来自锈蚀标准库unzip

代码语言:javascript
复制
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)
}

这两行:

代码语言:javascript
复制
ts.extend(SizeHint(lo, hi, marker::PhantomData));
us.extend(SizeHint(lo, hi, marker::PhantomData));

实际上不要将tsus扩展为任何东西,因为SizeHintnext方法返回None。这样做的目的是什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-06 14:36:40

这是个很酷的把戏。通过给出这个大小提示,它使tsus有机会为循环中的extend调用预留空间。根据documentation

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

注意,创建SizeHint是必要的,因为extend调用for循环使用Some值(Optional实现Iterator特性),而Some值的size_hint(1, Some(1))。这对预先分配没有帮助。

但是,看看Vec的代码,这不会有任何影响(在HashMapVecDeque中都不会)。其他的Extend实现可能不同。

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

代码语言:javascript
复制
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);
            }
        }
    }
}
票数 5
EN

Stack Overflow用户

发布于 2016-05-06 19:44:57

这是个可疑的黑客!

它使用假的(高估的)大小提示实现迭代器,以鼓励生成的集合预先保留最终适当的容量。

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37074656

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档