... которая может либо извлекать (и возвращать ссылку) объект черты другой черты, либо создавать (и возвращать его в штучной упаковке).
С этим требованием Box
не будет работать. A Box
владеет своими данными, но иногда вы заимствовали данные, которые нельзя переместить.
В стандартной библиотеке есть тип с именем Cow
, который является абстракцией того, является ли значение заимствованным или принадлежащим. Тем не менее, он может быть не совсем подходящим для вас, потому что он не позволит вам владеть данными как Box
, а также требует, чтобы ваш тип данных реализовывал ToOwned
.
Но мы можем принять ваше требование и смоделировать его непосредственно как enum
:
enum BoxOrBorrow<'a, T: 'a + ?Sized> {
Boxed(Box<T>),
Borrowed(&'a T),
}
И сделать его эргономичным, используя Deref
:
use std::ops::Deref;
impl<'a, T> Deref for BoxOrBorrow<'a, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
BoxOrBorrow::Boxed(b) => &b,
BoxOrBorrow::Borrowed(b) => &b,
}
}
}
Это позволяет вам обрабатывать пользовательский тип BoxOrBorrow
как любую другую ссылку - вы можете разыменовать его с помощью *
или передать его любой функции, которая ожидает ссылку на T
.
Вот как будет выглядеть ваш код:
trait ProducerOrContainer {
fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>>;
}
impl<'b, B: Borrow<dyn A>> ProducerOrContainer for HashMap<&'b str, B> {
fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>> {
self.get(name)
.map(|b| BoxOrBorrow::Borrowed(b.borrow()))
}
}