#macro #traits #downcast #any #own #object #person

mopa-maintained

我的个人 Any:获得具有附加功能的 Any

1 个不稳定版本

使用旧的 Rust 2015

0.2.3 2022 年 7 月 8 日

#2692Rust 模式

42 每月下载量

MIT/Apache

21KB
144

MOPA:我的个人 Any

Build Status

一个宏,用于在您自己的 trait 上实现所有 Any 方法。

你喜欢 Any — 它能够将任何 'static 类型存储为 trait 对象,然后将其下转换为原始类型,这非常方便,实际上你可能出于某种错误的原因需要它。但是,这还不够。你真正想要的是具有 Any 功能的自己的 trait 对象类型。也许你有一个 Person trait,并希望你的个人能够做各种事情,但你同时还想方便地将个人下转换为它的原始类型,对吧?唉,你现在不能写像 Box<Person + Any> 这样的类型(至少目前不能)。那么你该怎么办呢?你是要放弃吗?不,不!不,不!请进入 MOPA。

曾经有一个非常友好的 trait
名为 Person,有很多事情要做。
    “我需要是 Any
    以下转换为 Benny
但我不是,所以我想我只能等待。”

这是一个悲惨的故事,不是吗?特别是考虑到有一只熊在追赶它,意图吃掉它。幸运的是,现在你可以通过三个简单步骤来 mopafy Person

  1. 像往常一样将 mopa crate 添加到你的 Cargo.toml 中,就像这样

    #[macro_use]
    extern crate mopa;
    
  2. Any (mopa::Any,而不是 std::any::Any) 作为 Person 的超 trait;

  3. mopafy!(Person);.

看哪,现在你可以随心所欲地编写 person.is::<Benny>()person.downcast_ref::<Benny>() 等等。简单,对吧?

顺便说一句,其实是在熊盘上的人。在 Person 的盘子上实际上什么也没有。

#[macro_use]
extern crate mopa;

struct Bear {
    // This might be a pretty fat bear.
    fatness: u16,
}

impl Bear {
    fn eat(&mut self, person: Box<Person>) {
        self.fatness = (self.fatness as i16 + person.weight()) as u16;
    }
}

trait Person: mopa::Any {
    fn panic(&self);
    fn yell(&self) { println!("Argh!"); }
    fn sleep(&self);
    fn weight(&self) -> i16;
}

mopafy!(Person);

struct Benny {
    // (Benny is not a superhero. He can’t carry more than 256kg of food at once.)
    kilograms_of_food: u8,
}

impl Person for Benny {
    fn panic(&self) { self.yell() }
    fn sleep(&self) { /* ... */ }
    fn weight(&self) -> i16 {
        // Who’s trying to find out? I’m scared!
        self.yell();
        self.kilograms_of_food as i16 + 60
    }
}

struct Chris;

impl Chris {
    // Normal people wouldn’t be brave enough to hit a bear but Chris might.
    fn hit(&self, bear: &mut Bear) {
        println!("Chris hits the bear! How brave! (Or maybe stupid?)");
        // Meh, boundary conditions, what use are they in examples?
        // Chris clearly hits quite hard. Poor bear.
        bear.fatness -= 1;
    }
}

impl Person for Chris {
    fn panic(&self) { /* ... */ }
    fn sleep(&self) { /* ... */ }
    fn weight(&self) -> i16 { -5 /* antigravity device! cool! */ }
}

fn simulate_simulation(person: Box<Person>, bear: &mut Bear) {
    if person.is::<Benny>() {
        // None of the others do, but Benny knows this particular
        // bear by reputation and he’s *really* going to be worried.
        person.yell()
    }
    // If it happens to be Chris, he’ll hit the bear.
    person.downcast_ref::<Chris>().map(|chris| chris.hit(bear));
    bear.eat(person);
}

fn main() {
    let mut bear = Bear { fatness: 10 };
    simulate_simulation(Box::new(Benny { kilograms_of_food: 5 }), &mut bear);
    simulate_simulation(Box::new(Chris), &mut bear);
}

现在你真的应该这样做吗?可能不是。对于这种情况,枚举可能是一个更好的解决方案;坦白说,我几乎认为你唯一应该向下转换 Any 特性对象(或修改过的特性对象)的情况是使用泛型参数,例如在生成类似 AnyMap 的东西时。如果你控制 所有 的代码,Any 特性对象可能不是正确的解决方案;它们适用于跨多个库的用户定义类型的情况。但是目的和适宜性的问题仍然是开放的,目前我这里没有很好的用例。待办事项。

用法

一路使用 Cargo。 http://crates.io/crates/mopa

作者

Chris Morgan (chris-morgan) 是这个库的主要作者和维护者。

许可证

这个库的发行条款类似于 Rust:MIT 许可证和 Apache 许可证(版本 2.0)的双重许可。

有关详细信息,请参阅 LICENSE-APACHE、LICENSE-MIT 和 COPYRIGHT。

无运行时依赖项

功能