1 个不稳定版本

0.1.0 2023 年 7 月 28 日

#1324Rust 模式

Apache-2.0

185KB
275

Hereditary

通过扩展基于其组合(因为它们包含实现所需功能的其他类型的实例)的结构体中的特性功能,在 Rust 中模拟面向对象继承的进程宏。

Composition Over Inheritance

Hereditary 通过 转发 其结构体字段中引用的包含实例所实现的所需方法,生成组合结构体特性实现的样板代码。

目前,Hereditary 支持 2 种委托类型

  • 部分委托:通过在特性实现上使用装饰器属性 #[forward_trait(submember)]
  • 完全委托:通过在组合结构体上应用 #[derive(Forwarding)],它从属性 #[forward_derive(Trait)] 派生出特性实现(指定为属性)。

注意

在此处的文档页面中了解更多信息 https://docs.rs/hereditary

特性

  • 通过一条指令在组合结构体上实现子类型多态,将新类型赋予与其组件相同的接口。
  • 重用其他类型的字段/方法实现作为子组件,无需重复编写转发这些子组件方法的自定义代码。
  • Hereditary 工具本质上是一种 零成本抽象。它们不需要运行时结构来存储特性类型信息。所有工作都由宏和代码生成完成。
  • 有效地拥抱 新类型模式,但无需像以前那样繁琐地重新实现 inner-type 接口。通过使用这种技术,Rust 程序员可以避免将新行为整合到现有外部类型时的问题,绕过 特质孤儿规则

用法

在您的仓库中安装

cargo add hereditary

在您的代码中插入 hereditary

mod animal {
    // Attribute macro for generating trait info
    #[hereditary::trait_info]
    pub trait Cannis {
        fn bark(&self)-> String;
        fn sniff(&self)-> bool; 
    }
    #[hereditary::trait_info]
    pub trait Bird {
       fn sing(&self) -> String;
       fn fly(&mut self, elevation:f64) -> f64; 
    }
}

// Heritance for an hybrid animal
#[derive(hereditary::Forwarding)]
struct KimeraSphinx 
{    
    #[forward_derive(animal::Cannis)] // full implementation of Cannis
    dogpart:Bulldog,
    birdpart:Seagull
}

// Combining existing trait implementation from Seagull instance
#[hereditary::forward_trait(birdpart)]
impl animal::Bird for KimeraSphinx
{
    fn sing(&self) -> String
    {
        self.dogpart.bark()
    }
}

// -- Subcomponent implementations -- //
struct Bulldog { position:f64 }
impl animal::Cannis for Bulldog { 
    //... Cannis methods ...
}
struct Seagull {  elevation:f64 }
impl animal::Bird for Seagull {
     //... Bird methods ...
}

fn main() {
    // Instance kimera
    let mut kimera = KimeraSphinx::new();
    // A dogs that flies.
    assert_eq!(kimera.fly(50f64), 50f64);
    assert_eq!(kimera.bark(), kimera.sing()); // It barks instead of singing
    assert_eq!(kimera.sniff(), true);
}

限制

  • 由于宏的使用非常频繁,使用 Hereditary 生成的代码会经历更长的编译过程。
  • 有时,外部模块无法引用特质信息,因为生成的 trait_info 宏不像其对应的特质那样自动导入。这就是为什么它们需要在使用转发属性时使用完整路径(例如 animal::Bird),而不是仅仅使用 Bird。这是与声明性宏及其可见性作用域规则相关的一个已知问题,因为当将它们作为模块符号 导出时,它们有特殊的需求。

许可证

Apache 2.0

作者: Francisco Leon

依赖项

~1.5–2MB
~29K SLoC