为什么在Iterator trait对象上调用next会给我“内存不足"的提示?在运行时? [英] Why does calling next on an Iterator trait object give me an "out of memory" at runtime?

查看:134
本文介绍了为什么在Iterator trait对象上调用next会给我“内存不足"的提示?在运行时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Rust中实现了BoxedIterator,它只是将另一个Iterator装箱为特征对象.完整的实现在 Github 上.为什么Rust第一次尝试在Box中的Iterator特征对象上调用next时,Rust会在没有抱怨的情况下编译此代码,但失败并显示内存不足"消息(OOM)?

I implemented a BoxedIterator in Rust that just boxes another Iterator as a trait object. The full implementation is on Github. Why does Rust compile this code without complaint but fail with an "out of memory" message (OOM) when it first tries to call next on the Iterator trait object in the Box?

据我所知,它在失败之前不会分配太多内存,因此我倾向于认为OOM消息不正确.

As far as I can tell it doesn't allocate much memory before failing, so I'm inclined to think the OOM message is not correct.

//! BoxedIterator just wraps around a box of an iterator, it is an owned trait object.
//! This allows it to be used inside other data-structures, such as a `Result`.
//! That means that you can `.collect()` on an `I where I: Iterator<Result<V, E>>` and get out a
//! `Result<BoxedIterator<V>, E>`. And then you can `try!` it. At least, that was my use-case.

use std::iter::FromIterator;
use std::iter::IntoIterator;

pub struct BoxedIterator<T> {
    iter: Box<Iterator<Item = T>>,
}

impl<T> Iterator for BoxedIterator<T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next() // The OOM comes from this call of `next`
    }
}

impl<T> FromIterator<T> for BoxedIterator<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item = T>,
              I::IntoIter: 'static
    {
        BoxedIterator { iter: Box::new(iter.into_iter()) }
    }
}

use std::fs::File;
use std::io;

fn main() {
    let iter: Result<BoxedIterator<File>, io::Error> =
        vec!["/usr/bin/vi"].iter().cloned().map(File::open).collect();
    let mut iter = iter.unwrap();

    println!("{:?}", iter.next());
}

我认为我不会使用此代码,因为我发现我的用例将需要完全遍历ResultIterator以提取任何错误,因此我也很可能会收集此时将它们放在Vec中.但是我仍然对这个OOM感到好奇.

I don't think I'm going to use this code, as I've figured that my use case will need to traverse the Iterator of Results completely to extract any errors so I might as well gather them in a Vec at that point. But I'm still curious about this OOM.

在创建一个最小示例时,我发现没有执行文件IO,我会遇到段错误:

While creating a minimal example, I found that without doing the File IO, I get a segfault:

use iterator::BoxedIterator;

fn main() {
    let iter: Result<BoxedIterator<&str>, ()> = 
        vec![Ok("test1"), Ok("test2")].iter().cloned().collect();
    let mut iter = iter.unwrap();

    println!("{:?}", iter.next());
}

如果我不使用任何Result,只需使用collect创建一个BoxedIterator,该代码将按预期工作:

If I don't use any Result, just create a BoxedIterator with collect, the code works as expected:

use iterator::BoxedIterator;

fn main() {
    let mut iter: BoxedIterator<&str> = vec!["test1", "test2"].iter().cloned().collect();

    println!("{:?}", iter.next());
    // prints: Some("test1")
}

推荐答案

您对FromIterator的实现不正确;特别是,您不允许在该位置放置I::IntoIter: 'static绑定.实现的边界必须与特征本身的边界匹配.编译器应该对此进行诊断,但目前没有.

Your implementation of FromIterator isn't correct; specifically, you aren't allowed to put an I::IntoIter: 'static bound in that position. The bounds on your implementation have to match the bounds on the trait itself. The compiler should diagnose this, but currently doesn't.

在更高级别上,我不确定您要做什么.您希望File句柄存储在哪里?您通常会这样写:

At a higher level, I'm not sure what you're trying to do. Where do you expect the File handles to be stored? You would normally write something like this:

let files: Result<Vec<File>, io::Error> =
    ["/bin/bash"].iter().cloned().map(File::open).collect();

这篇关于为什么在Iterator trait对象上调用next会给我“内存不足"的提示?在运行时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆