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
}
Any value type except Nullable<T> can be specified. You can also specify a generic parameter as a constraint. The type argument supplied for the type you're constraining must be or derive from the type of the constraint. This parameter is called a naked type constraint.
Constraints inform the compiler about the capabilities a type argument must have. Without any constraints, the type argument could be any type. The compiler can only assume the members of System.Object, which is the ultimate base class for any .NET type.
The use of a generic type parameter as a constraint is useful when a member function with its own type parameter has to constrain that parameter to the type parameter of the containing type, as shown in the following example: public class List<T> { public void Add<U> (List<U> items) where U : T {/*...*/}
The type argument must have a public parameterless constructor. When used together with other constraints, the new () constraint must be specified last. The new () constraint can't be combined with the struct and unmanaged constraints.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With