一、介绍
实现了Any trait,它可以'static
通过运行时反射实现任何类型的动态类型。pub trait Any: 'static + Reflect {
fn get_type_id(&self) -> TypeId;
}
Any在定义的时候就规定了其生命周期,而Reflect是一个Marker,默认所有的Rust类型都会实现他!注意,这里不是所有原生类型,而是所有类型。
- Any本身可以用来获取TypeId, 并且作为 trait 对象使用时具有更多的特性。
- 作为
&dyn Any
(借用的 trait 对象),它具有is 和downcast_ref方法,用于测试包含的值是否属于给定类型,并获取对内部值作为类型的引用。 - 作为
&mut dyn Any
,还有downcast_mut一种方法,用于获取对内部值的可变引用。 Box<dyn Any>
添加downcast方法,该方法尝试转换为Box<T>
。
二、例子
我们在编译时不知道我们的值的具体类型,所以我们需要使用运行时反射来代替。use std::fmt::Debug;
use std::any::Any;
// Logger function for any type that implements Debug.
fn log<T: Any + Debug>(value: &T) {
let value_any = value as &dyn Any;
// Try to convert our value to a `String`. If successful, we want to
// output the String`'s length as well as its value. If not, it's a
// different type: just print it out unadorned.
match value_any.downcast_ref::<String>() {
Some(as_string) => {
println!("String ({}): {}", as_string.len(), as_string);
}
None => {
println!("{:?}", value);
}
}
}
// This function wants to log its parameter out prior to doing work with it.
fn do_work<T: Any + Debug>(value: &T) {
log(value);
// ...do some other work
}
fn main() {
let my_string = "Hello World".to_string();
do_work(&my_string);
let my_i8: i8 = 100;
do_work(&my_i8);
}
看到 do_work函数中的泛型T
。要求其实现Any和Debug。通过value as &Any;
我们需要将传入的类型转化成一个 trait Object。
这样,value 就可以被堪称一个 Any 了。然后,我们通过 downcast_ref
来进行类型推断。如果类型推断成功,则 value 就会被转换成原来的类型。