How to impose a type constraint on the associated type of an associated type (e.g. Iterator::Item)?
Asked Answered
R

1

6

I'm trying to define a trait with an associated type. I also want the associated type to implement Iterator with its Item associated type implementing AsRef<str>.

While I know how to do it for a function or for a concrete Iterator::Item type, I can't come up with a clear and concise solution for the original case.

Thanks to the helpful error messages, my compiling solution is:

trait Note
where
    <<Self as Note>::FieldsIter as Iterator>::Item: AsRef<str>,
{
    type FieldsIter: Iterator;
    //other fields and methods omitted
}

The ugly where clause makes me think that there should be a better way.

This doesn't compile since Item: AsRef<str> is an illegal construction:

trait Note {
    type FieldsIter: Iterator<Item: AsRef<str>>;
    //other fields and methods omitted
}

This fails since impl is not allowed here:

trait Note {
    type FieldsIter: Iterator<Item = impl AsRef<str>>;
    //other fields and methods omitted
}

This doesn't compile since I want Iterator::Item to implement a certain trait, not to be a concrete type.

trait Note {
    type FieldsIter: Iterator<Item = AsRef<str>>;
    //other fields and methods omitted
}
Rialto answered 1/1, 2019 at 19:6 Comment(0)
H
7

You can make one small improvement, but otherwise the current syntax for this is as you have discovered:

trait Note
where
    <Self::FieldsIter as Iterator>::Item: AsRef<str>,
{
    type FieldsIter: Iterator;
}

This is the disambiguated syntax, the only problem is there isn't yet a way to make the ambiguous version! Rust issue #38078 is open to allow the Foo::Bar::Baz syntax.

RFC 2289 is also open as a way to improve this. With the RFC implemented, your second example should work:

trait Note {
    type FieldsIter: Iterator<Item: AsRef<str>>;
}

One way you can work around this now is similar to IntoIterator. This introduces another associated type:

trait Note {
    type FieldsIter: Iterator<Item = Self::Item>;
    type Item: AsRef<str>;
}

I'm not a fan of this because it introduces types that at first look to be orthogonal to each other, but in the end are tightly related.

Hoagy answered 1/1, 2019 at 19:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.