Comments 10
Можно по futures такую же, хотя это уже не сам язык, а его библиотека. Хотя у Rust документировано все классно на оф. сайте. Но для закрепления такое — самое то.
С итератором — не самый лучший пример, во многих языках итератор сделан именно как Iterator<T>
и никаких проблем этим нет. Тип T тут хоть и указывается вроде как внешним кодом, но реально точно так же задаётся реализацией, ведь только реализация решает какие трейты она реализует. А реализация двух итераторов и неоднозначный next — это выдуманная проблема, так просто не надо делать и всё.
Куда интереснее дело обстоит с вскользь упомянутыми коллекциями! Тот же трейт IntoIterator (называемый в Java Iterable, а в C# — IEnumerable), при попытке реализовать его как IntoIterator<T>
, начинает требовать динамической диспетчеризации для итератора. В принципе, его можно было бы реализовать и как IntoIterator<T, TIter: Iterator<T>>
— но это уже выглядит не так красиво, плюс ограничение TIter: Iterator<T>
пришлось бы дублировать при каждом упоминании IntoIterator.
Хотел было ответить, что можно же объявить метод в трейте IntoIterator<T>
как fn into_iter(self) -> impl Iterator<T>;
но тут внезапно осознал, что impl Trait
не поддерживается для методов трейта. Так что да, вы правы, спасибо за ценное дополнение.
А разве IntoIter
— это аналог IEnumerable<T>
? Насколько я помню, IEnumerable<T>
является наиболее абстрактным интерфейсом перечисляемой неизменяемой коллекции. А трейт IntoIter
забирает владение объектом. Что, вроде как, не позволяет писать такое:
fn foo<T>(collection: &AbstractCollection<T>) {...}
// do something with my_collection
foo(my_collection)
// do something with my_collection
А реализация абстрактного трейта коллекций требует, вроде как, HKT. Поправьте меня, если я не прав.
На пальцах: ассоциированные типы в Rust и в чём их отличие от аргументов типов