Rust标准库学习-Any

Any的定义

Any是标准库的一个trait特征,用于模拟/模仿动态类型。

Any提供的行为只有type_id方法,可以说几乎是一种空实现。

所有的rust类型都默认实现了Any

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: 'static + ?Sized> Any for T {
    fn type_id(&self) -> TypeId {
        TypeId::of::<T>()
    }
}

这里T显式约束了 ?Sized,表明既包括编译时的定长类型,也有运行时才能确定大小的DST类型(dynamically sized types)

Sized类型?Sized类型

rust中大多数类型是在编译时就能确定大小的,例如基本类型i32,引用&T,数组[T;N],容器Vec<T>(包含长度,容量,堆地址)

如果一个类型约束为Sized,那么显然它的对象都是具备一样的长度。

事实上,rust编译器默认为所有类型都添加了Sized约束,只有少量例外。

通过添加?Sized约束来解除默认的Sized约束,声明这些类型

1. 无法在编译期确定长度

2. 这些类型的实例在运行时可能有不同的长度

3. 对于这些类型只能通过引用/智能指针/容器去使用,例如 引用&,Box,Rc等。

常见的?Sized类型有 str,dyn SomeTrait

trait object

dyn SomeTrait也叫做trait object,它是一种特殊结构,包含两个部分,一是指向实现SomeTrait的实际对象t的指针,二是包含类型T实现了SomeTrait的特征方法表。

标准库和The book都没有对trait object做太详细的描述,我们只能知道它是一种运行时动态长度的结构。

有了trait object,我们可以在数组或集合中存放不同长度的对象,当然由于上面提到的?Sized必须由指针包裹,所以这种数组或集合的声明必须是 [Box<dyn SomeTrait>; N] 或者 Vec<&dyn SomeTrait>

下面回到Any的使用

Any的使用

Any的定义包含了Sized类型和DST类型,因此所有的rust类型都有了Any特征,那么dyn Any可以由任意类型创建。

Box<dyn Any>的downcast方法:尝试还原类型

fn print_if_string(value: Box<dyn Any>) {
    if let Ok(string) = value.downcast::<String>() {
        println!("String ({}): {}", string.len(), string);
    }
}
let my_string = "Hello World".to_string();
print_if_string(Box::new(my_string));
print_if_string(Box::new(0i8));

dyn Any的is方法:试探是否是某类型

fn is_string(s: &dyn Any) {
    if s.is::<String>() {
        println!("It's a string!");
    } else {
        println!("Not a string...");
    }
}
is_string(&0);
is_string(&"cookie monster".to_string());

这里注意创建trait object的时候,Box<dyn Any>需要转移原对象所有权,而&dyn Any只需要引用即可。

dyn Any的downcast_ref/downcast_mut方法:这个和Box<dyn Any>的downcast方法类似。

这种转换,将dyn Any转换成具体的对象,更确切的是进行"追溯寻找”,而和基础类型的as或者From/Into有所区别。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值