当特征具有关联类型时如何将特征实现存储在一起
How to store trait implementations together when the trait has associated types
当我们想在一个集合中存储多个类型时,可以使用 Trait 对象。
但是当特征有关联类型时,我不知道如何做到这一点。
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
完全相同,但 returns Box<dyn Error>
以防出错,因此它是对象安全的。例如,这只是在不修改 Trait
或其实现 StructA
和 StructB
:
的实现的情况下工作
fn main() {
let value: Box<dyn DynamicTrait> = match 0 {
0 => Box::new(StructA),
_ => Box::new(StructB),
};
}
当我们想在一个集合中存储多个类型时,可以使用 Trait 对象。
但是当特征有关联类型时,我不知道如何做到这一点。
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
完全相同,但 returns Box<dyn Error>
以防出错,因此它是对象安全的。例如,这只是在不修改 Trait
或其实现 StructA
和 StructB
:
fn main() {
let value: Box<dyn DynamicTrait> = match 0 {
0 => Box::new(StructA),
_ => Box::new(StructB),
};
}