When can you omit associated types?

Say I have this function:

fn map_add<I>(lane: I) -> impl Iterator<Item = u8>
where
    I: IntoIterator<Item = u8>,
{
    lane.into_iter().map(|v| v + 1)
}

Why do I not have to specify the associated type?

<I as IntoIterator>::IntoIter

You can omit them whenever you don't need to constrain the associated type for the purposes of your function body. For example, this function works with any IntoIter and any Item, so the where clause can be simple:

fn collect_vec<I>(it: I) -> Vec<I::Item>
where
    I: IntoIterator,
{
    it.into_iter().collect()
}

Your map_add function body requires I::Item = u8 (or another integer type), but it doesn't impose any requirements on I::IntoIter. You could certainly specify some additional constraint like

    where I: IntoIterator<
        Item = u8,
+       IntoIter = std::vec::IntoIter<u8>,
    >,

But you only have to specify the constraints that enable your function body to compile.

2 Likes

Associated types are outputs of implementations as well -- if you know the implementation, the associated types are uniquely determined. You don't need to specify the associated type to determine the implementation.

The implementation is uniquely determined by its inputs -- the implementing type and any generic parameters on the trait itself.

4 Likes

Ah, makes sense. I think I was wrapped around the axle with a compile error that I took the wrong impression from.