Я реализовал BoxedIterator
в Rust, который просто упаковывает другой Iterator
в качестве трейт-объекта. Полная реализация находится на Github. Почему Rust компилирует этот код без жалоб, но выдает сообщение «недостаточно памяти» (OOM) при первой попытке вызвать next
для трейт-объекта Iterator
в Box
?
Насколько я могу судить, он не выделяет много памяти перед сбоем, поэтому я склонен думать, что сообщение OOM неверно.
//! 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());
}
Я не думаю, что буду использовать этот код, так как я полагал, что мой вариант использования должен будет полностью пройти Iterator
из Result
, чтобы извлечь любые ошибки, поэтому я мог бы также собрать их в Vec
в этот момент. Но мне все еще интересно узнать об этом OOM.
При создании минимального примера я обнаружил, что без выполнения файлового ввода-вывода я получаю 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
, просто создаю BoxedIterator
с collect
, код работает так, как ожидалось:
use iterator::BoxedIterator;
fn main() {
let mut iter: BoxedIterator<&str> = vec!["test1", "test2"].iter().cloned().collect();
println!("{:?}", iter.next());
// prints: Some("test1")
}