Как реализовать признак, когда невозможно назвать один из связанных типов?

#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