Generics 在Rust中没有trait对象的情况下,如何在trait的多个实现者之间进行选择?
我有一个名为Generics 在Rust中没有trait对象的情况下,如何在trait的多个实现者之间进行选择?,generics,rust,Generics,Rust,我有一个名为Dataset的特性,它有一个单一的方法来通过文件名和相关的错误类型检索文件内容。该特性是针对不同的文件系统结构实现的,例如用于基于目录的访问的PathBuf,或用于在压缩zip存档中访问的ZipArchive。出于测试目的,还存在一个用于HashMap的实现 trait数据集{ 类型错误:错误+'静态; fn read(&mut self,name:&str)->结果; } 现在,我想根据给定的文件名来推断要使用的实现:如果路径是一个目录,一个zip存档,如果扩展名是“代码> .
Dataset
的特性,它有一个单一的方法来通过文件名和相关的错误
类型检索文件内容。该特性是针对不同的文件系统结构实现的,例如用于基于目录的访问的PathBuf
,或用于在压缩zip存档中访问的ZipArchive
。出于测试目的,还存在一个用于HashMap
的实现
trait数据集{
类型错误:错误+'静态;
fn read(&mut self,name:&str)->结果;
}
现在,我想根据给定的文件名来推断要使用的实现:如果路径是一个目录,一个zip存档,如果扩展名是“代码> .zip 或<代码> .bzip ,等等。考虑一个函数<代码> fnRun(DataSet:IMPL DataSet)< /COD>,它运行在一个数据集上。内联选择代码后,一切正常:(使用
选项
仅适用于本例,实际代码查看上述给定路径的属性)
let optional=Some(PathBuf::from(“/path/to/dataset/.txt”);
匹配可选。克隆(){
一些(数据集)=>运行(数据集)?,
None=>run(static_dataset())?,
}
但是,我更愿意将(1)“为数据集
选择一个实现者”的功能从(2)“将数据集
赋予运行
功能”中分离出来。我希望使这个功能更可重用(不仅是<代码>运行/代码>函数可以使用(1),并且更独立于<代码>运行< /代码> -考虑对签名的更改,如添加更多的参数。
我尝试了两种方法:
fn与_trait_对象(可选:选项)->Box{
选配{
一些(数据集)=>Box::new(数据集),
None=>Box::new(静态_数据集),
}
}
但这将被拒绝,并显示错误消息:
error[E0191]: the value of the associated type `Error` (from trait `Dataset`) must be specified
--> src/main.rs:68:60
|
9 | type Error: Error + 'static;
| ---------------------------- `Error` defined here
...
68 | fn with_trait_object(optional: Option<PathBuf>) -> Box<dyn Dataset> {
|
可以在上找到一个小示例。您可以从以下内容开始:
fn with_consumer_function<DS: Dataset>(
optional: Option<DS>,
consumer: impl FnOnce(DS) -> Result<(), Box<dyn Error>>,
) -> Result<(), Box<dyn Error>> {
match optional {
Some(dataset) => consumer(dataset),
None => todo!(), //consumer(static_dataset()),
}
}
也就是说,使用DatasetConsumer
比使用普通闭包更麻烦
您也可以尝试将_consumer _function作为宏来实现
,但我不确定是否会遵循此路径。您可以从以下内容开始:
fn with_consumer_function<DS: Dataset>(
optional: Option<DS>,
consumer: impl FnOnce(DS) -> Result<(), Box<dyn Error>>,
) -> Result<(), Box<dyn Error>> {
match optional {
Some(dataset) => consumer(dataset),
None => todo!(), //consumer(static_dataset()),
}
}
也就是说,使用DatasetConsumer
比使用普通闭包更麻烦
您也可以尝试将_consumer _function
作为宏来实现,但我不确定我是否会遵循这条路径。此外,我还曾尝试让编译器接受它。这是你的电话号码
但我认为@Phimueme有一个非常简洁的回答。在我的例子中,为了方便起见,我添加了一个枚举,而不是一个关联的类型。在代码中,只需将运行闭包映射到选项
,即可避免泛型。我不确定它是否符合分解匹配臂的标准,但它感觉很方便,并且避免了动态调度。此外,我还尝试过让编译器接受它。这是你的电话号码
但我认为@Phimueme有一个非常简洁的回答。在我的例子中,为了方便起见,我添加了一个枚举,而不是一个关联的类型。在代码中,只需将运行闭包映射到选项
,即可避免泛型。我不确定它是否符合分解匹配臂的标准,但它感觉很方便,并且避免了动态调度。没有trait objects/我不会从思想上拒绝[trait objects]。当你提出一个要求(“没有”)然后说“不要担心这个要求”时,不清楚如何回答你的问题。@Shepmaster,标题中提出这个要求的原因是我一般可以使用trait对象,但在我的具体案例中,trait对象不起作用。如果你对它有不同的说法,我很乐意使用它。没有特质对象/我不会在意识形态上拒绝[特质对象]。当你提出一个要求(“没有”)然后说“不要担心这个要求”时,不清楚如何回答你的问题。@Shepmaster,标题中提出这个要求的原因是我一般可以使用trait对象,但在我的具体案例中,trait对象不起作用。如果您对它有不同的措辞,我很乐意应用它。我希望您指出,使用enum
而不是关联类型可以更灵活地使用此特性。但是,在您的方法中,我看不出如何在另一个使用者函数中进行交换–它们在实际代码中比我在示例中展示的简单的使用者
复杂得多。我希望您指出,使用枚举
而不是关联类型将能够更灵活地使用此特性。但是,在您的方法中,我看不出如何在另一个消费者函数中进行交换–它们在实际代码中比我在示例中展示的简单的消费者
复杂得多