是否可以在运行时检查对象是否实现了特征? [英] Is it possible to check if an object implements a trait at runtime?
问题描述
trait Actor{
fn actor(&self);
}
trait Health{
fn health(&self);
}
struct Plant;
impl Actor for Plant{
fn actor(&self){
println!("Plant Actor");
}
}
struct Monster{
health: f32
}
impl Actor for Monster{
fn actor(&self){
println!("Monster Actor");
}
}
impl Health for Monster{
fn health(&self){
println!("Health: {}",self.health);
}
}
fn main() {
let plant = Box::new(Plant);
let monster = Box::new(Monster{health: 100f32});
let mut actors : Vec<Box<Actor>> = Vec::new();
actors.push(plant);
actors.push(monster);
for a in &actors{
a.actor();
/* Would this be possible?
let health = a.get_trait_object::<Health>();
match health{
Some(h) => {h.health();},
None => {println!("Has no Health trait");}
}
*/
}
}
我想知道这样的事情是否可能?
I am wondering if something like this could be possible?
let health = a.get_trait_object::<Health>();
match health{
Some(h) => {h.health();},
None => {println!("Has no Health trait");}
}
推荐答案
目前在 Rust 中不可能做到这一点,也不太可能成为可能;但是,可以构建类似的抽象作为特征的一部分:
It is not possible to do this in Rust at present, nor is it likely to ever become possible; it is, however, possible to construct similar abstractions as part of your trait:
trait Actor {
fn health(&self) -> Option<&Health>;
}
trait Health { }
impl Actor for Monster {
fn health(&self) -> Option<&Health> { Some(self) }
}
impl Health for Monster { }
impl Actor for Plant {
fn health(&self) -> Option<&Health> { None }
}
Rust 预计会在某个时候获得负边界;届时,您将能够拥有这样的东西:
Rust is expected to get negative bounds at some point; when that comes, you’ll be able to have something like this:
trait MaybeImplements<Trait: ?Sized> {
fn as_trait_ref(&self) -> Option<&Trait>;
}
macro_rules! impl_maybe_implements {
($trait_:ident) => {
impl<T: $trait_> MaybeImplements<$trait_> for T {
fn as_trait_ref(&self) -> Option<&$trait_> {
Some(self)
}
}
impl<T: !$trait_> MaybeImplements<$trait_> for T {
fn as_trait_ref(&self) -> Option<&$trait_> {
None
}
}
}
}
impl_maybe_implements!(Health);
trait Actor: MaybeImplements<Health> {
}
let health: Option<&Health> = actor.as_trait_ref();
这会将样板从每个特征的实现减少到每个特征一个,但那个阶段还没有到来.不过,您可以采取两种方法的中间立场:
This will reduce the boilerplate from every implementation of a trait to just one per trait, but that stage is not yet upon us. Still, you could take the middle ground of the two approaches:
trait MaybeImplements<Trait: ?Sized> {
fn as_trait_ref(&self) -> Option<&Trait>;
}
macro_rules! register_impl {
($trait_:ident for $ty:ty) => {
impl MaybeImplements<$trait_> for $ty {
fn as_trait_ref(&self) -> Option<$trait_> {
Some(self)
}
}
}
(!$trait_:ident for $ty:ty) => {
impl MaybeImplements<$trait_> for $ty {
fn as_trait_ref(&self) -> Option<$trait_> {
None
}
}
}
}
register_impl!(Health for Monster);
register_impl!(!Health for Plant);
尝试不同的处理方式,直到找到您喜欢的东西!可能性是无限的!(因为 Rust 是图灵完备的.)
Play around with different ways of handling it until you find something you like! The possibilities are limitless! (Because Rust is Turing‐complete.)
这篇关于是否可以在运行时检查对象是否实现了特征?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!