#generics #rust #traits #associated-types
#дженерики #Ржавчина #Трейты #связанные типы
Вопрос:
У меня есть функция, которая возвращает an impl Trait
, поэтому у меня нет доступа к конкретному возвращаемому типу. Мне нужно использовать возвращаемое значение этой функции в качестве связанного типа в признаке. Как мне это сделать?
Вот упрощенный пример:
fn f() -> impl Iterator<Item = u8> {
std::iter::empty()
}
struct S;
impl IntoIterator for S {
type Item = u8;
type IntoIter = (); // What can I write here ?
fn into_iter(self) -> Self::IntoIter {
f()
}
}
Возможно ли это вообще (не прибегая к боксированию итератора)?
Комментарии:
1. Хвала хорошо сформулированному вопросу с соответствующим MCVE!
Ответ №1:
К сожалению, вы не можете. По крайней мере, пока.
Существует RFC с именем existentials и объявления переменных признака impl (проблема с отслеживанием), который позволил бы вам объявлять имя общедоступного типа на уровне модуля, определение типа которого выводится из того, как оно используется в модуле. Пользователи модуля могут ссылаться на этот тип по его общедоступному имени, и он может использоваться как связанный тип.
Трудно угадать, когда новая функция стабилизируется, а пока хороших вариантов действительно не так много. Помимо вещей, которые могут работать только из-за специфики вашего варианта использования, общим обходным путем является использование объекта признака:
impl IntoIterator for S {
type Item = u8;
type IntoIter = Box<dyn Iterator<Item = u8>>;
fn into_iter(self) -> Self::IntoIter {
Box::new(f())
}
}
Если допустимо использовать функции nightly, вы можете помочь протестировать RFC до его стабилизации:
#![feature(existential_type)]
impl IntoIterator for S {
type Item = u8;
existential type IntoIter: Iterator<Item = u8>;
fn into_iter(self) -> Self::IntoIter {
f()
}
}
Комментарии:
1. Спасибо за этот четкий ответ. Тогда я собираюсь использовать поле. И чувствую себя преданным rust, который обещал мне абстракции с нулевой стоимостью: p