Is it a bug that stop recognize &[i32;3] as &[i32]?

When I tried to construct an iter with

    std::iter::once(&[1001, nums[0], nums[1]])
        .chain(nums.windows(3))
        .chain(std::iter::once(&[nums[nums.len() - 2], nums[nums.len() - 1], 1001]))

rustc tells me,

Line 4, Char 10: type mismatch resolving `<Windows<'_, i32> as IntoIterator>::Item == &[i32; 3]` (solution.rs)
    |
4   |         .chain(nums.windows(3))
    |          ^^^^^ expected array `[i32; 3]`, found slice `[i32]`
    |
    = note: expected reference `&[i32; 3]`
               found reference `&[i32]`
note: required by a bound in `std::iter::Iterator::chain`
Line 5, Char 10: the method `chain` exists for struct `std::iter::Chain<std::iter::Once<&[i32; 3]>, Windows<'_, i32>>`, but its trait bounds were not satisfied (solution.rs)
     |
5    |           .chain(std::iter::once(&[nums[nums.len() - 2], nums[nums.len() - 1], 1001]))
     |            ^^^^^ method cannot be called on `std::iter::Chain<std::iter::Once<&[i32; 3]>, Windows<'_, i32>>` due to unsatisfied trait bounds
     |
     = note: the following trait bounds were not satisfied:
             `<Windows<'_, i32> as Iterator>::Item = &[i32; 3]`
             which is required by `std::iter::Chain<std::iter::Once<&[i32; 3]>, Windows<'_, i32>>: Iterator`
             `std::iter::Chain<std::iter::Once<&[i32; 3]>, Windows<'_, i32>>: Iterator`
             which is required by `&mut std::iter::Chain<std::iter::Once<&[i32; 3]>, Windows<'_, i32>>: Iterator`
Some errors have detailed explanations: E0271, E0599.
For more information about an error, try `rustc --explain E0271`.
error: could not compile `prog` due to 2 previous errors

I believed that, it is due to the incompleteness of rust's type inference system.

Thus I put .as_slice to the first element,

    std::iter::once([1001, nums[0], nums[1]].as_slice())
        .chain(nums.windows(3))
        .chain(std::iter::once(&[nums[nums.len() - 2], nums[nums.len() - 1], 1001]))

but there is still an error:

Line 5, Char 10: type mismatch resolving `<std::iter::Once<&[i32; 3]> as IntoIterator>::Item == &[i32]` (solution.rs)
    |
5   |         .chain(std::iter::once(&[nums[nums.len() - 2], nums[nums.len() - 1], 1001]));
    |          ^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected reference `&[i32]`
               found reference `&[i32; 3]`
note: required by a bound in `std::iter::Iterator::chain`
For more information about this error, try `rustc --explain E0271`.
error: could not compile `prog` due to previous error

I know that, put as_slice to both line could make the program compiles, but why rust could not corece this array to slice here?

Well, the conversion to &[i32] has to happen before you pass it as an argument to once, but the compiler will only coerce it there if &[i32] is the only type that once accepts. Since once can accept an &[i32; 3] too, it will not be coerced automatically in that position, even if that choice leads to trouble later.

6 Likes

Because type inference and coercion are mortal enemies.

The eventual answer to your problem will be https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.array_windows, since you would rather get arrays than slices anyway,

-        .chain(nums.windows(3))
+        .chain(nums.array_windows())

but for now you'll just need

-    std::iter::once(&[1001, nums[0], nums[1]])
+    std::iter::once(&[1001, nums[0], nums[1]][..])

manually.

8 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.