bioball
bioball

Reputation: 1359

Cannot resolve core::slice::Iter as core::iter::Iterator?

I'm trying to write a simple iterator in Rust:

#[derive(Debug)]
pub struct StackVec<'a, T: 'a> {
    storage: &'a mut [T],
    len: usize,
    _head: usize,
}

impl<'a, T> IntoIterator for StackVec<'a, T> {
    type Item = T;
    type IntoIter = core::slice::Iter<'a, T>;

    fn into_iter(self) -> core::slice::Iter<'a, T> {
        self.storage.iter()
    }
}

However, when trying to compile it, I'm getting this error:

error[E0271]: type mismatch resolving `<core::slice::Iter<'_, T> as core::iter::Iterator>::Item == T`
   --> src/lib.rs:135:13
    |
135 | impl<'a, T> IntoIterator for StackVec<'a, T> {
    |             ^^^^^^^^^^^^ expected reference, found type parameter
    |
    = note: expected type `&T`
               found type `T`

error: aborting due to previous error

error: Could not compile `stack-vec`.

There's a couple things that are confusing about this error message. For one, it seems like Rust isn't able to resolve a core::slice::Iter as core::iter::Iterator. But, core::slice::Iter is an iterator, right? Why aren't these types matching up?

Secondly, I'm seeing an error around expecting IntoIterator to be a reference rather than a type parameter. However, it's not a type parameter to begin with. What's that about?

What am I doing wrong here? What's Rust trying to tell me about my code?

Upvotes: 5

Views: 1249

Answers (2)

Dan Hulme
Dan Hulme

Reputation: 15290

There's a couple things that are confusing about this error message.

You're dead right, it's quite a hard message to parse.

it seems like Rust isn't able to resolve a core::slice::Iter as core::iter::Iterator

You're dead wrong: you mis-parsed the message by missing some angle brackets. (I said it was hard to parse!) Let's look at the message, with some crucial bracketing highlighted:

type mismatch resolving `<core::slice::Iter<'_, T> as core::iter::Iterator>::Item == T`
                         (________________________________________________)

The problem isn't resolving core::slice::Iter<'_, T> as core::iter::Iterator, it's resolving the equality, where the whole expression <core::slice::Iter<'_, T> as core::iter::Iterator>::Item is the left-hand side. That whole mess names a single type: it's the type you get by using the as operator to upcast core::slice::Iter<'_, T> to core::iter::Iterator, and then take the Item member of it.

The trait IntoIterator is defined as follows:

pub trait IntoIterator where
    <Self::IntoIter as Iterator>::Item == Self::Item

That is, to implement the trait, you need to satisfy the requirement given. This is the requirement the compiler is complaining about. You've defined Item as T, and IntoIter as core::slice::Iter<'_, T>, but putting those two definitions in doesn't satisfy the equality.

Put another way, to implement IntoIterator, you need to define an Item type, it needs to be the same as your underlying iterator's Item type. core::slice::Iter<'a, T> defines its Item type like this:

type Item = &'a T

so you need the same definition in your impl block.

Here's a Playground with your definition fixed, and an empty main() so it'll compile.

Upvotes: 7

Steve Klabnik
Steve Klabnik

Reputation: 15559

For one, it seems like Rust isn't able to resolve a core::slice::Iter as core::iter::Iterator. But, core::slice::Iter is an iterator, right? Why aren't these types matching up?

You're missing the crucial part of the message:

type mismatch resolving <std::slice::Iter<'_, T> as std::iter::Iterator>::Item == T

It can't resolve it *as an iterator with the Item type as T.

This is because slice::Iter is an iterator over references, not values.

Upvotes: 2

Related Questions