#枚举 #代理 #变体 #密封 #动态分派

proxy-enum

使用代理枚举模拟动态分派和密封类,将所有方法调用推迟到其变体上

4个版本 (2个重大更新)

0.3.1 2021年1月7日
0.3.0 2020年11月24日
0.2.0 2020年4月30日
0.1.2 2020年4月28日
0.1.1 2020年4月28日

#密封中排名第8

MIT许可证

18KB
239

proxy-enum

Crate API

使用代理枚举模拟动态分派和"密封类",将所有方法调用推迟到其变体上。

简介

在Rust中,动态分派是通过特质对象(dyn Trait)实现的。它们使我们能够实现运行时多态性,一种表示类型实现特定特质而忽略其实际实现的方法。

let animal: &dyn Animal = random_animal();
animal.feed(); // may print "mew", "growl" or "squeak"

然而,特质对象也有缺点:从特质对象(向下转换)获取具体实现是痛苦的。(见 std::any::Any

如果你知道只有有限数量的实现可以与之交互,那么enum可能更适合表示这种关系

enum Animal {
    Cat(Cat),
    Lion(Lion),
    Mouse(Mouse)
}

match random_animal() {
    Animal::Cat(cat) => cat.feed(),
    Animal::Lion(lion) => lion.feed(),
    Animal::Mouse(mouse) => mouse.feed()
}

一些语言为此类类型提供了特殊支持,例如Kotlin的所谓"密封类"。

然而,Rust 并不 支持。

proxy-enum通过过程宏简化了此类类型的处理。

用法

#[proxy_enum::proxy(Animal)]
mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    impl Animal {
        #[implement]
        fn feed(&self) {}
    }
}

这将扩展为

mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    impl Animal {
        fn feed(&self) {
            match self {
                Animal::Cat(cat) => cat.feed(),
                Animal::Lion(lion) => lion.feed(),
                Animal::Mouse(mouse) => mouse.feed()
            }
        }
    }  

    impl From<Cat> for Animal { /* ... */ }
    impl From<Lion> for Animal { /* ... */ }
    impl From<Mouse> for Animal { /* ... */ }
}

然而,只有当CatLionMouse都具有名为feed的方法时,这段代码才能编译。由于Rust有特质来表达通用功能,因此也可以生成特质的实现

#[proxy_enum::proxy(Animal)]
mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    trait Eat {
        fn feed(&self);
    }

    #[implement]
    impl Eat for Animal {}
}

由于宏必须知道特质包含哪些方法,因此它必须在模块内部定义。然而,也可以生成外部特质的实现

#[proxy_enum::proxy(Animal)]
mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    #[external(std::string::ToString)]
    trait ToString {
        fn to_string(&self) -> String;
    }

    #[implement]
    impl std::string::ToString for Animal {}
}

依赖项

~1.5MB
~33K SLoC