5 个版本
0.2.4 | 2022 年 11 月 10 日 |
---|---|
0.2.3 | 2022 年 9 月 25 日 |
0.2.2 | 2022 年 9 月 23 日 |
0.2.1 | 2022 年 9 月 22 日 |
0.2.0 | 2022 年 8 月 28 日 |
在 Rust 模式 中排名 1212
每月下载量 21 次
40KB
412 行代码(不包括注释)
trait_cast_rs
要求
此 crate 需要夜间编译器。
此 crate 能做什么?
此 crate 为 Any
添加了 TraitcastableAny
替换 trait。它类似于 Any
trait,用于向下转换为具体类型。此外,TraitcastableAny
trait 允许您直接向下转换为其他 &dyn Trait
。
要使此功能正常工作,您必须在 make_trait_castable(Trait1, Trait2, ...)
属性宏中指定所有要向下转换的目标 traits。此宏可以应用于结构体、枚举和联合体。它为您指定的结构体、枚举或联合体实现了 TraitcastableAny
trait。
注意:无需修改目标 traits。这允许您向下转换为不受您控制的库中的 traits。
用法
-
将
trait_cast_rs
crate 添加到您的Cargo.toml
并切换到夜间编译器。 -
将
#[make_trait_castable(Trait1, Trait2, ...)]
宏添加到您的结构体/枚举/联合体中。列出您最终想要向下转换的所有 traits。您必须实现所有列出的 traits。 -
在整个代码中使用
dyn TraitcastableAny
的引用,而不是dyn Any
。 -
享受向下转换为 trait 对象。
示例
use trait_cast_rs::{
make_trait_castable, TraitcastableAny, TraitcastableAnyInfra, TraitcastableAnyInfraExt,
};
#[make_trait_castable(Print)]
struct Source(i32);
trait Print {
fn print(&self);
}
impl Print for Source {
fn print(&self) {
println!("{}", self.0)
}
}
let source = Box::new(Source(5));
let castable: Box<dyn TraitcastableAny> = source;
let x: &dyn Print = castable.downcast_ref().unwrap();
x.print();
更多示例 🔥
查看 示例。
如果您想要做一些make_trait_castable
属性宏无法处理的操作(例如实现泛型结构体 - 欢迎提交pull请求),请查看manual*.rs
示例。
还有可用的声明宏 - 查看示例with_decl_macro*.rs
。
功能
-
alloc
- 为Box
、Rc
和Arc
添加特殊实现。默认功能。 -
const_sort
- 使make_trait_castable
和make_trait_castable_decl
宏在编译时
对traitcast_targets
进行排序。当执行向下转换时,将执行二分搜索。对于具有大量向下转换目标类型的类型,可能会非常快。此外,用户代码还需要以下功能标志:
#![feature(const_trait_impl, const_mut_refs)]
-
min_specialization
- 为'static
类型实现TraitcastableAny
。即使是您无法控制的类型。然而,这些TraitcastableAny
的默认实现没有向下转换目标。此外,用户代码还需要以下功能标志:
#![feature(min_specialization)]
-
downcast_unchecked
- 向向下转换函数添加*_unchecked
变体。
向上转换为真正的Any
使用trait_upcasting
rust功能,您甚至可以将任何&dyn TraitcastableAny
转换为&dyn Any
。或者,您可以将Any
特质作为特质转换目标。但是,无法将其转换回TraitcastableAny
(欢迎提交pull请求)。
作者
raldone01和onestacked是此库的主要作者和维护者。
许可证
该项目可以在以下许可证下发布:
由您选择。
贡献
除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据Apache-2.0许可证定义,均将按照上述方式双许可,不附加任何其他条款或条件。
它是如何工作的
我将简要介绍我们的内部操作:💦
编译时
-
为每个向下转换路径向具体类型添加一个
casting
函数。此函数接收一个dyn TraitcastableAny
,然后使用背景中的Any
将其向下转换为具体类型。最后,它将具体类型转换为所需的特质对象并返回它。 -
添加一个返回常量切片的
traitcast_targets
函数,其中包含(typeid
,转换的casting函数指针)。
运行时
- 获取目标数组
- 查找目标
typeid
- 将函数指针转换回原始类型
- 调用函数指针以获取所需的特质对象
- 返回它
- 💲 利润 💲
安全性 🏰
- 所有未检查的
downcast
函数变体都使用unsafe
- 如预期。 - 不安全使用的另一个用途是函数指针的转换。然而,当它们被调用时,它们会转换回原始类型。所以这应该是
105%
保存的。只要TypeId
不冲突。
替代方案 (以及为什么我们的 crate 是最好的)
本替代方案部分并不全面,如需更客观/详细的比较,请参阅 cast_trait_object 的替代方案部分。
- mopa:最后一次更新是在6年前。有一些未解决的 不安全性问题。还要求对特质的本身进行修改,而我们已经修改了结构体/枚举/联合体(见上面的注释)。
- mopa-maintained:可能已修复一些问题,但代码库仍然很旧,只是版本升级。
- traitcast:在 crates.io 上没有提供说明文档。使用全局注册表,并带有
lazy_static
。公平地说,它允许您使用默认的Any
,并且不需要 nightly。
待办事项:一旦我们的最后一次更新是在6年前,就删除此部分。
链接
依赖
~215–295KB