5个版本
0.2.2 | 2021年8月17日 |
---|---|
0.2.1 | 2020年10月28日 |
0.2.0 | 2020年4月24日 |
0.1.1 | 2020年4月17日 |
0.1.0 | 2020年3月22日 |
#497 in Rust模式
1,822 每月下载量
用于 43 个crate (5 直接)
32KB
446 行
Intertrait
此库提供类型间实现的特质对象之间的直接转换。
在Rust中,如果已知类型,则可以将在子特质std::any::Any
的特质对象在运行时转换为具体类型。但是,两个特质对象之间没有直接的转换(即不涉及支持值的具体类型)是可能的(甚至还没有从特质的特质对象到其超特质的强制转换)。
使用此crate,任何CastFrom
子特质的特质对象,如果目标特质预先通过此crate提供的宏注册,则可以直接转换为底层类型实现的另一个特质的特质对象。
依赖项
将以下两个依赖项添加到您的 Cargo.toml
[dependencies]
intertrait = "0.2"
linkme = "0.2"
linkme
依赖项是必需的,因为linkme
宏在intertrait
宏的输出中使用。
用法
use intertrait::*;
use intertrait::cast::*;
struct Data;
trait Source: CastFrom {}
trait Greet {
fn greet(&self);
}
#[cast_to]
impl Greet for Data {
fn greet(&self) {
println!("Hello");
}
}
impl Source for Data {}
fn main() {
let data = Data;
let source: &dyn Source = &data;
let greet = source.cast::<dyn Greet>();
greet.unwrap().greet();
}
目标特质必须事先明确指定。有三种方法可以做到这一点
#[cast_to]
到impl
项
指定的特质是实现目标特质。
use intertrait::*;
struct Data;
trait Greet { fn greet(&self); }
#[cast_to]
impl Greet for Data {
fn greet(&self) {
println!("Hello");
}
}
#[cast_to(Trait)]
到类型定义
对于类型,指定为#[cast_to(...)]
属性参数的特质被指定为目标特质。
use intertrait::*;
trait Greet { fn greet(&self); }
impl Greet for Data {
fn greet(&self) {
println!("Hello");
}
}
#[cast_to(Greet, std::fmt::Debug)]
#[derive(std::fmt::Debug)]
struct Data;
castable_to!(类型=>特质1,特质2)
对于类型,以下 :
特性被指定为目标特性。
use intertrait::*;
#[derive(std::fmt::Debug)]
struct Data;
trait Greet { fn greet(&self); }
impl Greet for Data {
fn greet(&self) {
println!("Hello");
}
}
// Only in an item position due to the current limitation in the stable Rust.
// https://github.com/rust-lang/rust/pull/68717
castable_to!(Data => Greet, std::fmt::Debug);
fn main() {}
Arc
支持
std::sync::Arc
的独特之处在于它仅在 dyn Any + Send + Sync + 'static'. 上实现
downcast
方法。要与 Arc
一起使用,应采取以下步骤
- 使用
CastFromSync
而不是CastFrom
标记源特性 - 将
[sync]
标志添加到#[cast_to]
和castable_to!
,如下所示#[cast_to([sync])] #[cast_to([sync] Trait1, Trait2)] castable_to!(Type => [sync] Trait, Trait2);
工作原理
首先,CastFrom
特性使得从 std::any::Any
对象中检索 std::any::Any
对象成为可能。
intertrait
提供的宏生成了将 std::any::Any
特性对象向下转换为其实际类型的跳转函数,并从其中创建目标特质的特性对象。
这些跳转函数使用 linkme
包聚合到全局注册表中,这涉及到没有(通常不鼓励的)main 之前的生命周期技巧。注册表由一对 TypeId
组成,它们是 CastFrom
子特质的特性对象的底层实际类型的 TypeId
和目标特质(这里的实际实现略有不同,但概念上是如此)。
在这个过程中,它不依赖于任何可能在未来更改的 Rust 不稳定实现细节,如特性对象的布局。
致谢
intertrait
从伟大的 traitcast
包中汲取了许多核心思想。
许可证
根据您的选择,受以下任何一个许可证的约束
- Apache License,版本 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交以包含在工作中的任何贡献,将根据上述方式双重许可,不附加任何额外的条款或条件。
依赖项
~2MB
~43K SLoC