1 个不稳定版本
使用旧的 Rust 2015
0.2.3 | 2022 年 7 月 8 日 |
---|
#2692 在 Rust 模式
42 每月下载量
21KB
144 行
MOPA:我的个人 Any
一个宏,用于在您自己的 trait 上实现所有 Any
方法。
你喜欢 Any
— 它能够将任何 'static
类型存储为 trait 对象,然后将其下转换为原始类型,这非常方便,实际上你可能出于某种错误的原因需要它。但是,这还不够。你真正想要的是具有 Any
功能的自己的 trait 对象类型。也许你有一个 Person
trait,并希望你的个人能够做各种事情,但你同时还想方便地将个人下转换为它的原始类型,对吧?唉,你现在不能写像 Box<Person + Any>
这样的类型(至少目前不能)。那么你该怎么办呢?你是要放弃吗?不,不!不,不!请进入 MOPA。
曾经有一个非常友好的 trait
名为Person
,有很多事情要做。
“我需要是Any
以下转换为Benny
—
但我不是,所以我想我只能等待。”
这是一个悲惨的故事,不是吗?特别是考虑到有一只熊在追赶它,意图吃掉它。幸运的是,现在你可以通过三个简单步骤来 mopafy Person
-
像往常一样将
mopa
crate 添加到你的Cargo.toml
中,就像这样#[macro_use] extern crate mopa;
-
将
Any
(mopa::Any
,而不是std::any::Any
) 作为Person
的超 trait; -
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。