trait对象中的Rust泛型方法



我正在尝试实现一个库,该库运行用各种语言编写的脚本,并从中提取一些可调用的对象。特别是,我对函数get_engine感兴趣,它通过指定文件扩展名返回给您一个工厂。目前的实施方式是:

#[cfg(test)]
mod tests;
use std::error::Error;
pub struct AutoLibrary<'a> {
engines: Vec<
Box<
dyn AutomationFactory<
'a,
dyn AutomationScript<'a, dyn AutomationCommand<'a>>,
dyn AutomationCommand<'a>,
dyn Error,
>,
>,
>,
}
impl<'a> AutoLibrary<'a> {
fn get_engine(
&self,
name: impl AsRef<str>,
) -> Box<
dyn AutomationFactory<
'a,
dyn AutomationScript<'a, dyn AutomationCommand<'a>>,
dyn AutomationCommand<'a>,
dyn Error,
>,
> {
todo!()
}
}
pub struct AssFile {/* doesn't matter for now */}
pub trait AutomationCommand<'a> {
fn call(&self, file: AssFile) -> AssFile;
}
pub trait AutomationScript<'a, C>
where
C: AutomationCommand<'a>,
{
fn commands(&self) -> Vec<C>;
}
pub trait AutomationFactory<'a, S, C, E>
where
C: AutomationCommand<'a>,
S: AutomationScript<'a, C>,
E: Error,
{
fn load_script(&self, path: impl AsRef<str>) -> Result<Box<S>, E>;
}

目前还没有编译。编译器试图告诉我,trait对象不能包含泛型方法,但并没有泛型方法,只有泛型实现。同样,对于那个特殊的案例,我无法理解其中的原因。编译器知道对象泛型的实际特性,因此可以构建并返回vtable,因为特性本身总是消耗&self,并且在最终实现中总是返回特定的对象。

由于impl AsRef<str>

load_script是通用的。参数位置的impl Trait本质上只是普通泛型的语法糖。以下是load_script如何降低:

pub trait AutomationFactory<'a, S, C, E>
where
C: AutomationCommand<'a>,
S: AutomationScript<'a, C>,
E: Error,
{
fn load_script<R: AsRef<str>>(&self, path: R) -> Result<Box<S>, E>;
}

正如您所看到的,函数是通用的。为了解决这个问题,我建议将其更改为accept和&str,并要求在呼叫站点进行转换:

pub trait AutomationFactory<'a, S, C, E>
where
C: AutomationCommand<'a>,
S: AutomationScript<'a, C>,
E: Error,
{
fn load_script(&self, path: &str) -> Result<Box<S>, E>;
}
// somewhere else
let path = String::new();
factory.load_script(&path);

最新更新