Возвращаемое значение get_subelem
не может пережить &self
заем, который вы использовали для его вызова, потому что подпись get_subelem
явно говорит об этом:
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
// ^^ ^^
Чтобы получитьBoxOrRef<'a, _>
, вы должны одолжить self
на всю жизнь 'a
.В вызывающей стороне elem
не может пережить замыкание, которому оно принадлежит, а get_subelem
занимает elem
, поэтому не может вернуть значение, которое может избежать этого замыкания.
Выпытаясь сделать что-то небезопасное, и компилятор правильно остановит вас.Теоретически, table.get_elem
может возвращать значение Boxed
, а elem.get_subelem
может возвращать внутреннюю ссылку, и тогда Box
будет отброшено при закрытии, что сделает недействительной ссылку.
Предположительно, чтона самом деле не происходит, поэтому вы должны сообщить об этом компилятору.Один из способов - отделить &self
от BoxOrRef<'a, _>
:
pub trait Elem<'a> {
fn get_subelem(&self, name: &str) -> Option<BoxOrRef<'a, dyn Elem<'a>>>;
}
. Приведенное выше изменение приведет к компиляции вашего примера, как только вы добавите параметры времени жизни ко всем Elem
s, но это поставит вас в неловкое положение.позиция при реализации Elem
: вы не можете вернуть ссылку на self
, поэтому практически все должно быть Boxed
.
Трудно дать хорошую рекомендацию, учитывая неопределенность примера, ноЯ предлагаю вам сделать шаг назад и подумать, является ли BoxOrRef
правильной абстракцией здесь.По сути, вы ничего не можете сделать с BoxOrRef
, что вы не можете сделать со ссылкой, потому что BoxOrRef
может быть ссылкой.В то же время, вы не можете ничего с этим сделать, что не можете сделать с Box
, потому что это может быть Box
.std::borrow::Cow
использует ToOwned
для реализации Clone
и into_owned
- возможно, подобный подход может работать для вас.(И если вы можете, возможно, просто внедрите ToOwned
для dyn Elem
и используйте Cow
напрямую.)