У меня есть следующий код:
use std::any::Any;
use std::borrow::Cow;
// Base trait for downcasting
pub trait AsTranslationUnit<'a> {
fn as_any(&self) -> &dyn Any;
}
pub trait TranslationUnit<'a>: AsTranslationUnit<'a> {
fn file_stem(&self) -> &Cow<'a, str>;
}
// Implementation of AsTranslationUnit for all types implementing TranslationUnit
impl<'a, T: TranslationUnit<'a> + 'a> AsTranslationUnit<'a> for T {
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct ModuleInterfaceModel<'a> {
pub file_stem: Cow<'a, str>,
}
impl<'a> TranslationUnit<'a> for ModuleInterfaceModel<'a> {
fn file_stem(&self) -> &Cow<'a, str> {
&self.file_stem
}
}
fn main() {
let model = ModuleInterfaceModel {
file_stem: Cow::Borrowed("example"),
};
let tu: &dyn TranslationUnit = &model;
if let Some(mi) = tu.as_any().downcast_ref::<ModuleInterfaceModel>() {
println!("Module Interface: {:?}", mi);
} else {
println!("Not a Module Interface");
}
}
Что приводит к следующей ошибке:
Compiling playground v0.0.1 (/playground)
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:16:9
|
16 | self
| ^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
14 | impl<'a, T: TranslationUnit<'a> + 'a + 'static> AsTranslationUnit<'a> for T {
| +++++++++
For more information about this error, try `rustc --explain E0310`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Я хотел бы привести любой тип TranslationUnit
к исходному типу, но все они содержат именованные параметры времени жизни, поэтому я не могу успешно применить этот подход.
Каким был бы более идиоматический подход к решению этой проблемы без дополнительных границ времени жизни 'static
(что, очевидно, не решает мою проблему) и без выхода из именованного параметра времени жизни в моих структурах?
@eggyal Я могу. Вы имеете в виду понижение его в реализациях признака для каждого реализатора? Или что-то подобное?
Черта может содержать реализацию функции по умолчанию, которая возвращает None
, а реализация ModuleInterfaceModel
может переопределить ее, просто вернув Some(self)
. Тогда вам вообще не нужно переходить через Any
: можно прямо вниз с &dyn TranslationUnit
.
Any
не поддерживает время жизни. Период.
Есть несколько ящиков, поддерживающих пожизненный Any
, например временный, но я не могу ручаться за их надежность, так как не проверял их.
Вот пример его использования:
use std::borrow::Cow;
use transient::{Any, Downcast, Inv, Transient};
// Base trait for downcasting
pub trait AsTranslationUnit<'a> {
fn as_any(&self) -> &dyn Any<Inv<'a>>;
}
pub trait TranslationUnit<'a>: AsTranslationUnit<'a> + Any<Inv<'a>> {
fn file_stem(&self) -> &Cow<'a, str>;
}
// Implementation of AsTranslationUnit for all types implementing TranslationUnit
impl<'a, T: TranslationUnit<'a> + 'a> AsTranslationUnit<'a> for T {
fn as_any(&self) -> &dyn Any<Inv<'a>> {
self
}
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Transient)]
pub struct ModuleInterfaceModel<'a> {
pub file_stem: Cow<'a, str>,
}
impl<'a> TranslationUnit<'a> for ModuleInterfaceModel<'a> {
fn file_stem(&self) -> &Cow<'a, str> {
&self.file_stem
}
}
fn main() {
let model = ModuleInterfaceModel {
file_stem: Cow::Borrowed("example"),
};
let tu: &dyn TranslationUnit = &model;
if let Some(mi) = tu.as_any().downcast_ref::<ModuleInterfaceModel>() {
println!("Module Interface: {:?}", mi);
} else {
println!("Not a Module Interface");
}
}
Хм... почти. Но я столкнулся с этой ошибкой после получения Transient для ModuleInterfaceModel<'a>
: черта Static
не реализована для project_model::modules::ModuleInterfaceModel<'a>
@AlexVergara Этот код компилируется, я проверил. Если у вас возникли проблемы с выводом, убедитесь, что все поля также выводятся Transient
.
ваш код компилируется и работает, как описано. Проблема заключалась в том, что в реальном коде у меня есть вложенные структуры, которые теперь также являются временными, но они должны быть Clone
, что отсутствует в описании ошибки, и я этого не заметил.
Вы могли бы добавить метод
fn as_module_interface_model(&self) -> Option<&ModuleInterfaceModel>
к своей чертеTranslationUnit
?