#traits #clone #partial-eq #derive #dyn

dynex

为动态Rust继承和派生对象不安全特性

2个版本

0.1.1 2024年6月26日
0.1.0 2024年6月26日

#297 in 过程宏

MIT许可证

25KB
400 代码行

dynex

为动态Rust继承和派生对象不安全特性。

简介

对象安全性是Rust中特质的属性,用于确定特质是否可以作为特质对象使用。然而,许多有用的特质不是对象安全的,例如ClonePartialEq

例如,你不能简单地写

pub trait Meta: Clone + PartialEq {}

#[derive(Clone, PartialEq)]
pub struct Foo {
    meta: Box<dyn Meta>,        // The trait `Meta` cannot be made into an object.
}

此crate提供了一个派生对象不安全特质的程序宏

use dynex::*;

#[dyn_trait]
pub trait Meta: Clone + PartialEq {}

#[derive(Clone, PartialEqFix)]
pub struct Foo {
    meta: Box<dyn Meta>,        // Now it works!
}

注意:PartialEqFixPartialEq有完全相同的行为,但它解决了Rust编译器的一个奇怪行为。对于其他特质,你可以直接派生原始特质名称。

基本示例

以下是如何使用此crate的基本示例

use std::fmt::Debug;
use dynex::*;

#[dyn_trait]
pub trait Meta: Debug + Clone + PartialEq {
    fn answer(&self) -> i32 {
        42
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct MetaImpl;

impl Meta for MetaImpl {}

#[derive(Debug, Clone, PartialEqFix)]
pub struct Foo {
    meta: Box<dyn Meta>,
}

fn main() {
    let foo1 = Foo { meta: Box::new(MetaImpl) };
    let foo2 = Foo { meta: Box::new(MetaImpl) };
    assert_eq!(foo1, foo2);
    let foo3 = foo1.clone();
    assert_eq!(foo3.meta.answer(), 42);
}

不可派生特质

Add特质为例

use std::fmt::Debug;
use std::ops::Add;
use dynex::*;

#[dyn_trait]
pub trait Meta: Debug + Add {}

#[derive(Debug)]
pub struct MetaImpl(String);

impl Meta for MetaImpl {}

impl Add for MetaImpl {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Self(self.0 + &rhs.0)
    }
}

pub struct Foo {
    pub meta: Box<dyn Meta>,
}

impl Add for Foo {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Self {
            // `Box<dyn Meta>` can be added!
            meta: self.meta + rhs.meta,
        }
    }
}

fn main() {
    let foo1 = Foo { meta: Box::new(MetaImpl("114".into())) };
    let foo2 = Foo { meta: Box::new(MetaImpl("514".into())) };
    let foo3 = foo1 + foo2;
    println!("{:?}", foo3.meta);    // MetaImpl("114514")
}

致谢

此crate受到以下crate的启发

许可证

MIT.

依赖关系

~250–690KB
~17K SLoC