2 个版本
0.1.1 | 2022年3月1日 |
---|---|
0.1.0 | 2022年2月28日 |
20 在 #downcast
每月 29 次下载
在 5 个 crate 中使用 (直接使用 4 个)
30KB
511 行
用于将 trait 对象向下造型为具体类型
lib.rs
:
https://github.com/fkoep/downcast-rs 该库参考了downcast-rs, 为 Box、Rc、Arc 实现了 downcast 接口(向下造型)
为什么不直接使用downcast-rs? downcast-rs 仅为 Box、Rc 提供了 downcast
, 未提供 Arc 的 downcast
方法
补充:你不应该再使用本库,后续可能删除本库,因为最新的 downcast-rs 已经提供了 Arc 的 downcast 接口(2021.5.21)
下面的注释,拷贝了downcast-rs的README.md, 并不说明本库的用法。 Rust 枚举非常适合已知所有变体的类型。但在需要实现用户定义类型容器的开放类型,如 trait 对象 时,则需要。在某些情况下,将 trait 对象转换回其原始的具体类型以访问附加功能和使用性能内联实现是很有用的。
downcast-rs
使用安全的 Rust 为 trait 对象添加了向下造型支持。它支持 类型参数、关联类型 和 约束。
为了使 trait 可向下造型,使其扩展 any::BoxAny
trait,并在其上调用 impl_downcast!
,如下所示
trait Trait: BoxAny {}
impl_downcast!(Trait);
// With type parameters.
trait TraitGeneric1<T>: BoxAny {}
impl_downcast!(TraitGeneric1<T>);
// With associated types.
trait TraitGeneric2: BoxAny { type G; type H; }
impl_downcast!(TraitGeneric2 assoc G, H);
// With constraints on types.
trait TraitGeneric3<T: Copy>: BoxAny {
type H: Clone;
}
impl_downcast!(TraitGeneric3<T> assoc H where T: Copy, H: Clone);
// With concrete types.
trait TraitConcrete1<T: Copy>: BoxAny {}
impl_downcast!(concrete TraitConcrete1<u32>);
trait TraitConcrete2<T: Copy>: BoxAny { type H; }
impl_downcast!(concrete TraitConcrete2<u32> assoc H=f64);
非泛型示例
// Import macro via `macro_use` pre-1.30.
#[macro_use]
extern crate any;
use any::BoxAny;
// To create a trait with downcasting methods, extend `BoxAny` and run
// `impl_downcast!()` on the trait.
trait Base: BoxAny {}
impl_downcast!(Base);
// Concrete types implementing Base.
#[derive(Debug)]
struct Foo(u32);
impl Base for Foo {}
#[derive(Debug)]
struct Bar(f64);
impl Base for Bar {}
fn main() {
// Create a trait object.
let mut base: Box<Base> = Box::new(Foo(42));
// Try sequential downcasts.
if let Some(foo) = base.downcast_ref::<Foo>() {
assert_eq!(foo.0, 42);
} else if let Some(bar) = base.downcast_ref::<Bar>() {
assert_eq!(bar.0, 42.0);
}
assert!(base.is::<Foo>());
// Fail to convert `Box<Base>` into `Box<Bar>`.
let res = base.downcast::<Bar>();
assert!(res.is_err());
let base = res.unwrap_err();
// Convert `Box<Base>` into `Box<Foo>`.
assert_eq!(42, base.downcast::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
}
具有关联类型和约束的泛型 trait 示例
// Can call macro via namespace since rust 1.30.
extern crate any;
use any::BoxAny;
// To create a trait with downcasting methods, extend `BoxAny` and run
// `impl_downcast!()` on the trait.
trait Base<T: Clone>: BoxAny { type H: Copy; }
downcast_rs::impl_downcast!(Base<T> assoc H where T: Clone, H: Copy);
// or: impl_downcast!(concrete Base<u32> assoc H=f32)
// Concrete types implementing Base.
struct Foo(u32);
impl Base<u32> for Foo { type H = f32; }
struct Bar(f64);
impl Base<u32> for Bar { type H = f32; }
fn main() {
// Create a trait object.
let mut base: Box<Base<u32, H=f32>> = Box::new(Bar(42.0));
// Try sequential downcasts.
if let Some(foo) = base.downcast_ref::<Foo>() {
assert_eq!(foo.0, 42);
} else if let Some(bar) = base.downcast_ref::<Bar>() {
assert_eq!(bar.0, 42.0);
}
assert!(base.is::<Bar>());
}