Я пытаюсь создать трейт, который может либо извлекать (и возвращать ссылку) объект трейта другого трейта, либо создавать его (и возвращать его коробочную версию), оставляя выбор разработчику (что означает, что мне нужно чтобы ограничить время жизни возвращаемого объекта временем жизни производителя). Однако я сталкиваюсь с ошибками:
use std::borrow::Borrow;
use std::collections::HashMap;
trait A {
fn foobar(&self) {
println!("!");
}
}
trait ProducerOrContainer {
fn get_a<'a>(&'a self, name: &'a str) -> Option<Box<dyn A + 'a>>;
}
impl<'b, B: Borrow<A>> ProducerOrContainer for HashMap<&'b str, B> {
fn get_a<'a>(&'a self, name: &'a str) -> Option<Box<dyn A + 'a>> {
self.get(name).map(|borrow| Box::new(borrow.borrow()))
}
}
Ошибка:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | self.get(name).map(|borrow| Box::new(borrow.borrow()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait A, found &A
|
= note: expected type `std::option::Option<std::boxed::Box<dyn A + 'a>>`
found type `std::option::Option<std::boxed::Box<&dyn A>>`
Что меня озадачивает, потому что я ожидал, что &A
тоже будет A
. Я пробовал impl<'a> A for &'a A
, но и это не помогает. Есть ли способ исправить это?
A
реализация признака не означает, что&A
реализует. Иногда может показаться, что это правда из-за поведения авто-ссылки и авто-размещения в Rust. Например, он автоматически разыщет переменную, чтобы вы могли ввестиfoo.bar()
вместо(*foo).bar()
. - person Peter Hall   schedule 16.09.2018Box<&dyn A>
? Бокс ссылки не кажется очень полезным. - person Peter Hall   schedule 16.09.2018name: &'a str
здесь излишне ограничен, потому что возвращаемая ссылка не привязана кname
. Возможно, у вас есть другие реализацииProducerOrContainer
, в которых возвращаемое значение является производным отname
, но если нет, избавление от'a
будет более гибким. - person trentcl   schedule 16.09.2018