generics - 当特征具有关联类型时如何将特征实现存储在一起
问题描述
当我们想要将多个类型一起存储在一个集合中时,可以使用特征对象。
但是当特征具有关联类型时,我不知道该怎么做。
trait Error {}
trait Trait {
type Error: Error;
fn set(&mut self, key: String, value: String) -> Result<(), Self::Error>;
}
struct StructA;
impl Trait for StructA {
type Error = ErrorA;
}
enum ErrorA {}
impl Error for ErrorA {}
struct StructB;
impl Trait for StructB {
type Error = ErrorB;
}
enum ErrorB {}
impl Error for ErrorB {}
fn main() -> Result<(), Box<dyn Error>> {
let value: Box<dyn Trait<Error = dyn Error>> = match 0 {
0 => Box::new(StructA),
_ => Box::new(StructB),
};
value.set(String::from("key"), String::from("value"))?;
Ok(())
}
我必须在Box<dyn Trait<Error = _>>
这里指定关联的类型,但我不知道哪种类型适合。我试过dyn Error
了,但它不起作用。
解决方案
如果可以更改Trait
,则可以通过返回动态错误类型来使其对所有错误类型都是对象安全的,例如将签名更改为set()
:
fn set(&mut self, key: String, value: String) -> Result<(), Box<dyn Error + '_>>;
但是,如果您无法更改Trait
以使其对象安全,您仍然可以创建自己的对象安全特征,并为实现的每种类型提供一揽子实现Trait
。例如:
trait DynamicTrait {
fn set(&mut self, key: String, value: String) -> Result<(), Box<dyn Error + '_>>;
}
impl<T: Trait> DynamicTrait for T {
fn set(&mut self, key: String, value: String) -> Result<(), Box<dyn Error + '_>> {
Trait::set(self, key, value).map_err(|e| Box::new(e) as _)
}
}
DynamicTrait
工作方式与 完全相同Trait
,但Box<dyn Error>
在出错时返回,因此它是对象安全的。例如,这只是在不修改任何一个Trait
或其实现的实现的情况下工作StructA
,并且StructB
:
fn main() {
let value: Box<dyn DynamicTrait> = match 0 {
0 => Box::new(StructA),
_ => Box::new(StructB),
};
}
推荐阅读
- postgresql - Docker 从 yml postgres 数据库 url 错误组成
- docker - Docker Compose:将输出记录到文件和标准输出
- sql - 按问题分组 GreenPlum
- python-sphinx - 将代码类型传递给 Sphinx `.. include::` 指令
- rust - 如何避免`#[global_allocator]`冲突?
- amazon-web-services - 尚未为演示项目创建 EKS 入口的公共地址
- ios - 将 Swift 应用程序连接到 AWS 数据库
- influxdb-2 - InfluxDB Flux查询每组最后一条记录
- neo4j - neo4j 按可选属性按降序排列,空值位于底部
- python - 尝试在 Python 中对谷歌字体进行 base64 编码时出现问题