Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

rust

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?

like image 208
bioball Avatar asked Feb 21 '18 16:02

bioball


People also ask

What is the reverse version of iterator try_fold?

This is the reverse version of Iterator::try_fold (): it takes elements starting from the back of the iterator. Read more An iterator method that reduces the iterator’s elements to a single, final value, starting from the back. Read more Searches for an element of an iterator from the back that satisfies a predicate. Read more

What does an iterator do in Python?

This has the same lifetime as the original slice, and so the iterator can continue to be used while this exists. Converts this type into a shared reference of the (usually inferred) input type. Returns a copy of the value. Read more Performs copy-assignment from source. Read more Formats the value using the given formatter. Read more

What is fallible iteration?

An iterator method that applies a fallible function to each item in the iterator, stopping at the first error and returning that error. Read more Folds every element into an accumulator by applying an operation, returning the final result. Read more Reduces the elements to a single one, by repeatedly applying a reducing operation. Read more


2 Answers

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.

like image 156
Dan Hulme Avatar answered Oct 17 '22 09:10

Dan Hulme


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.

like image 44
Steve Klabnik Avatar answered Oct 17 '22 11:10

Steve Klabnik