#traits #dyn #generic #macro #generics #impl-block

traitify-core

将impl块转换为trait的宏。这是traitify crate的逻辑。

1个不稳定版本

0.1.0 2023年6月6日

#21#impl-block


traitify 中使用

MIT/Apache

12KB
172

Traitify

crates.io Documentation

你应该使用这个crate吗?

不。可能不是。

我为什么创建这个crate?

嗯,有时候你有一个泛型类型,需要将其传递给一个不能有泛型的函数。如果Rust有类似的语法那就太棒了

struct Foo<BAR, const FIZZ: usize>;

fn buzz(foo: &Foo<dyn, dyn>) {}

看我在那里做了什么?这个想象中的语法中在泛型类型的地方用dyn替换,会即时将其变成一个trait对象!酷吧?

遗憾的是这个语法并不存在,而且真的没有类似的东西。

那么,有哪些可行的方法呢?

基本上有两种方法。

如果你知道你泛型的所有不同变体,你可以创建一个枚举,并在该枚举上重新实现所有 Foo 函数。

如果你不知道,你可以创建一个包含 Foo 所有函数的trait,并为 Foo 实现这个trait。但写一个只由一个类型实现的trait感觉是不对的。感觉就像写一个C头文件,我就完成了头文件的编写。

这就是这个crate的作用所在!

这个crate只包含一个可以应用于impl块的宏。你告诉它所需的trait名称和应该忽略哪些泛型类型。

use traitify::traitify;

struct Foo<BAR, const FIZZ: usize> {
    data: [BAR; FIZZ],
};

#[traitify(FooDynFizz, dyn = [FIZZ])]
#[traitify(FooDynBAR, dyn = [BAR])]
#[traitify(FooDynAll, dyn = [FIZZ, BAR])]
impl<BAR, const FIZZ: usize> Foo<BAR, FIZZ> {
    pub fn print_greeting(&self) {
        println!("Hallo vriendjes en vriendinnetjes!");
    }
}

#[test]
fn compiles() {
    let foo = Foo::<u8, 4> { data: [0; 4] };
    let dyn_foo: &dyn FooDynAll = &foo;
    dyn_foo.print_greeting();
}

现在,我尽力让这个宏处理尽可能多的语法。但如果你发现有些东西不工作,而应该是工作的,那么请提交一个问题或PR!

以下是一个(可能不完整)的列表,说明哪些函数会出现在生成的trait中

  • 函数必须是公开的(这不是技术要求,否则你将通过公开的trait泄漏私有函数)
  • 函数不得有属于dyn列表的泛型类型的参数
  • 函数不得指定ABI
  • 函数必须有一个接收器参数(self, &self 或 &mut self)。它将在特质中,但会为对象安全性添加一个 Self: Sized 约束。对于特质对象来说并不十分有用,但添加起来很简单。

无法擦除生命周期。我认为应该可以,但我还没有做到。

依赖项

~250–700KB
~17K SLoC