11次发布
使用旧的Rust 2015
0.2.2 | 2016年4月5日 |
---|---|
0.2.1 | 2016年1月22日 |
0.2.0 | 2015年5月13日 |
0.1.8 | 2015年4月13日 |
0.1.4 | 2015年1月29日 |
#445 在 Rust模式
12,289 每月下载量
用于 238 个crate(17 直接)
21KB
157 行
mopa 0.2.2
MOPA: 我自己的个性Any。 一个宏,用于在您的自定义特质上实现所有Any
方法。
你喜欢Any
——它将任何'static
类型存储为特质对象,然后将其转回原始类型的功能非常方便,实际上无论出于何种错误的原因,你都需要它。但是这还不够。你真正想要的是具有Any
功能的自定义特质对象类型。也许你有一个Person
特质,你想让你的个人能做各种事情,但你还想能够方便地将人转回其原始类型,对吧?唉,你现在不能写一个像Box<Person + Any>
(至少现在不能)。那么你怎么办?放弃吗?不,不!不,不!来吧,MOPA。
曾经有一个非常友好的特质
叫做Person
,肩负重任。
“我需要成为Any
以转回Benny
——
但我不是,所以我猜我只好等着。”
一个可怜的故事,不是吗?尤其是考虑到还有一只熊在追它,打算吃掉它。幸运的是,现在你可以用三个简单步骤将Person
mopafy
-
像往常一样将
mopa
crate添加到你的Cargo.toml
中,就像crate根一样#[macro_use] extern crate mopa;
-
将
Any
(mopa::Any
,而不是std::any::Any
)作为Person
的超特质; -
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);
}
现在您应该这样做吗?可能不是。对于这个特定的案例,枚举可能是一个更好的解决方案;坦白地说,我相信您几乎只有在生产类似 AnyMap
这样的泛型参数时,才应该向下转型 Any 特质对象(或修改过的特质对象)。如果您控制了所有代码,Any
特质对象可能不是正确的解决方案;它们适用于跨多个库的用户定义类型的情况。但关于目的和适用性的问题仍然是开放的,目前我没有一个很好的用例来展示这种情况。待办事项。
用法
使用 Cargo。 http://crates.io/crates/mopa
作者
Chris Morgan (chris-morgan) 是这个库的主要作者和维护者。
许可协议
这个库以与 Rust 相似的方式分发:双重许可,受 MIT 许可证和 Apache 许可证(版本 2.0)的约束。
有关详细信息,请参阅 LICENSE-APACHE、LICENSE-MIT 和 COPYRIGHT。