1

I have three following examples:

fn iterate_with_iterator<T: std::fmt::Display, I: Iterator<Item = T>>(iter: I) {
    for x in iter {
         println!("{}", x);
    }
}

fn iterate_with_boxed_iterator<'a, T: std::fmt::Display>(iter: Box<dyn Iterator<Item = T> + 'a>) {
    for x in iter {
         println!("{}", x);
    }
}

fn iterate_with_deref_boxed_iterator<'a, T: std::fmt::Display>(iter: Box<dyn Iterator<Item = T> + 'a>) {
    let diter = *iter;
    for x in diter {
         println!("{}", x);
    }
}

Playground

When compiling the iterate_with_deref_boxed_iterator the following error appears:

error[E0277]: the size for values of type `dyn std::iter::Iterator<Item = T>` cannot be known at compilation time
  --> src/main.rs:14:9
   |
14 |     let diter = *iter;
   |         ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator<Item = T>`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature

error[E0277]: the size for values of type `dyn std::iter::Iterator<Item = T>` cannot be known at compilation time
  --> src/main.rs:15:14
   |
15 |     for x in diter {
   |              ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator<Item = T>`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `std::iter::IntoIterator::into_iter`

Why does dereferencing break compilation?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alex
  • 9,891
  • 11
  • 53
  • 87

1 Answers1

2

It is impossible to move any trait object (the dyn Iterator part of your type) out from behind a pointer (&dyn Iterator, Box<dyn Iterator>). This is because trait objects are unsized – the compiler does not have information about the concrete size of the referent object, and so will not allow moving it into the stack where its size must be known at compile time. This is what your error message ("the trait std::marker::Sized is not implemented for dyn std::iter::Iterator<Item = T>") means.

Rust does not support runtime-variable stack allocations at this time, so moving unsized values like trait objects into the stack is not allowed.

If you really need to unbox the iterator, you can make a generic function

fn deref_boxed<I: Iterator<Item = T>, T: Display>(iter: Box<I>) {
    let mut i = *iter;
    for item in i {
        println!("{}", item);
    }
}

but you should be able to iterate through the argument without unboxing it:

fn iter_boxed<'a, T: Display>(iter: Box<dyn Iterator<Item = T> + 'a>) {
    for item in iter {
        println!("{}", x);
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
myrrlyn
  • 151
  • 1
  • 4