你不能。 Traits 不支持向下转型 - Rust 不是基于继承/子类型的语言,它为您提供了另一组抽象。此外,你想做的事情是不合理的 - 特征是开放的(每个人都可以为任何事情实现它们),所以即使在你的情况下match *f
涵盖了所有可能的情况,一般来说编译器无法知道这一点。
这里你有两个选择。如果您提前知道实现您的特征的结构集,只需使用枚举,它是一个完美的工具。它们允许您静态匹配一组封闭的变体:
enum FooBar {
Foo(u32),
Bar(u32),
}
fn test(v: bool) -> FooBar {
if v {
FooBar::Foo(5)
} else {
FooBar::Bar(10)
}
}
fn main() {
let f: FooBar = test(true);
// Now that we have a `Box<Base>` (`*f` makes it a `Base`),
// let's handle different cases:
match f {
FooBar::Foo(x) => println!("it was Foo: {}!", x),
FooBar::Bar(y) => println!("it was Bar: {}!", y),
}
}
()
这是迄今为止最简单的方法,并且应该始终是首选方法。
另一种方法是使用Any http://doc.rust-lang.org/std/any/特征。它是一种从特征对象到常规类型的类型安全向下转换的工具:
use std::any::Any;
struct Foo {
x: u32,
}
struct Bar {
y: u32,
}
fn test(v: bool) -> Box<Any + 'static> {
if v {
Box::new(Foo { x: 5 })
} else {
Box::new(Bar { y: 10 })
}
}
fn main() {
let f: Box<Any> = test(true);
match f.downcast_ref::<Foo>() {
Some(&Foo { x }) => println!("it was Foo: {}!", x),
None => match f.downcast_ref::<Bar>() {
Some(&Bar { y }) => println!("it was Bar: {}!", y),
None => unreachable!(),
},
}
// it will be nicer when `if let` lands
// if let Some(ref Foo { x }) = f.downcast_ref::<Foo>() {
// println!("it was Foo: {}!", x);
// } else if let Some(ref Bar { y }) = f.downcast_ref::<Bar>() {
// println!("it was Bar: {}!", y);
// } else { unreachable!() }
}
()
理想情况下应该可以写成这样:
trait Base: Any {}
impl Base for Foo {}
impl Base for Bar {}
然后使用Base
在代码中,但现在无法完成,因为特征继承不适用于特征对象(例如,不可能从Box<Base>
to Base<Any>
).