Это работает, если вы явно указываете, что возвращаемый объект признака (dyn Iterator
) содержит ссылки, привязанные к времени жизни self
.
Без добавления этой границы компилятор не может сделать выводиз сигнатуры функции, что итератор не может быть использован после перемещения или уничтожения self
. Поскольку компилятор не может вывести это, он не может безопасно использовать self.map.keys()
в выходных данных функции.
Рабочий пример с добавленной границей:
pub trait Graph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a>;
}
use std::collections::HashMap;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>,
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a> {
let keys = self.map.keys();
Box::new(keys)
}
}
Playground
Я думал, что также потребуется граница Item = &'a N
, но я думаю, что это уже охватывается "+ 'a
" ...
NB, чтобы иметь смыслошибка типа:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
Вы должны понимать, что компилятор по эргономическим причинам автоматически добавляет квалификатор времени жизни + 'static
к любому неквалифицированному объекту черты. Это означает, что неквалифицированный Box<dyn MyTrait>
преобразуется компилятором в Box<(dyn MyTrait + 'static)>
, что, в свою очередь, означает, что объект не может содержать любых ссылок, кроме тех, которые существуют в течение всего времени жизни программы. Имея это в виду, вы можете понять, почему self.map.keys()
не соответствует этой строгой границе, и требуется более конкретная явная граница.