rust

How would calling into_iter on Box<[T; N]> behave?


I didn't realize that calling into_iter on Box<[T]> would return an iterator over references before edition 2024 until I read Edition Guide. This makes me curious about how calling into_iter on Box<[T; N]> does now (in edition 2024), given that Box<[T; N]> does not yet implement IntoIterator.

According to the The Dot Operator section of The Rustonomicon, it should first dereference to &[T; N], then unsize to &[T], suggesting that it should behave like calling into_iter on Box<[T]> used to — returning an iterator over references. However, this compiles:

struct Foo;

fn take(val: Foo) {}

fn main() {
    let array: Box<[Foo; 1]> = Box::new([Foo]);
    for foo in array.into_iter() {
        take(foo);
    }
}

Is it because the mysterious DerefMove is doing something?

(About the DerefMove, I know it does not exist. Some people think there should be a DerefMove trait to cancel the uniqueness of Box, so I use this term here just to describe this dereference behavior of Box)


Solution

  • Is it because the mysterious DerefMove is doing something?

    There is no DerefMove. Box is a lang_item which means the compiler can understand that a Box can be moved-from, unlike other pointers.

    The items you quote are about slices, but Box<[T; N]> is a boxed array not a slice. So it can deref to the array, which then invokes

    impl<T, const N: usize> IntoIterator for [T; N]
    

    which was added in edition 2021 in Rust 1.53

    demo on godbolt, note how the code compiles in Edition 2021, but not in Edition 2018

    And if you remove the -O and look at the assembly you can see that it references array::iter_inner, whereas boxed slices go through vec::into_iter::IntoIter, which you can also see if you replace the boxed array Box<[Foo; 1]> by a boxed slice Box<[Foo]>.