Module std::any

1.0.0 · source ·
Expand description

用于动态类型或类型反射的实用工具。

AnyTypeId

Any 本身可以用来得到一个 TypeId,当用作 trait 对象时,它有更多的特性。 作为 &dyn Any (借用的 trait 对象),它具有 isdowncast_ref 方法,以测试所包含的值是否为给定类型,并对该类型的内部值进行引用。 作为 &mut dyn Any,还有 downcast_mut 方法,用于获取内部值的变量引用。 Box<dyn Any> 添加了 downcast 方法,该方法尝试转换为 Box<T>。 有关完整的详细信息,请参见 Box 文档。

请注意,&dyn Any 仅限于测试值是否为指定的具体类型,而不能用于测试某个类型是否实现 trait。

智能指针和 dyn Any

Any 用作 trait 对象时要记住的一种行为,尤其是对于 Box<dyn Any>Arc<dyn Any> 之类的类型,只需在值上调用 .type_id() 即可生成容器的 TypeId,而不是底层 trait 对象。

可以通过将智能指针转换为 &dyn Any 来避免,这将返回对象的 TypeId。 例如:

use std::any::{Any, TypeId};

let boxed: Box<dyn Any> = Box::new(3_i32);

// 您更可能希望这样做:
let actual_id = (&*boxed).type_id();
// ... 比这个:
let boxed_id = boxed.type_id();

assert_eq!(actual_id, TypeId::of::<i32>());
assert_eq!(boxed_id, TypeId::of::<Box<dyn Any>>());
Run

Examples

考虑一下我们要注销传递给函数的值的情况。 我们知道我们正在实现的值实现了 Debug,但是我们不知道它的具体类型。我们要对某些类型进行特殊处理:在这种情况下,应先打印 String 值的长度,然后再打印它们的值。 我们在编译时不知道我们值的具体类型,因此我们需要使用运行时反射。

use std::fmt::Debug;
use std::any::Any;

// 用于实现 Debug 的任何类型的 Logger 函数。
fn log<T: Any + Debug>(value: &T) {
    let value_any = value as &dyn Any;

    // 尝试将我们的值转换为 `String`。
    // 如果成功,我们希望输出 String 的长度及其值。
    // 如果不是,那就是另一种类型:只需将其打印出来即可。
    match value_any.downcast_ref::<String>() {
        Some(as_string) => {
            println!("String ({}): {}", as_string.len(), as_string);
        }
        None => {
            println!("{value:?}");
        }
    }
}

// 该函数要先注销其参数,然后再使用它。
fn do_work<T: Any + Debug>(value: &T) {
    log(value);
    // ...做一些其他的工作
}

fn main() {
    let my_string = "Hello World".to_string();
    do_work(&my_string);

    let my_i8: i8 = 100;
    do_work(&my_i8);
}
Run

ProviderDemand

Provider 和相关的 API 支持泛型、类型驱动的数据访问,以及实现者提供此类数据的机制。 该接口的关键部分是用于提供数据的对象的 Provider trait,以及用于从实现 Provider 的对象请求数据的 request_valuerequest_ref 函数。 通常,最终用户不应该直接调用 request_*,它们是中间实现者用来实现面向用户的接口的辅助函数。 这纯粹是为了人体工程学,这里没有安全问题; 中间实现者通常可以支持方法而不是 free 函数,并使用更具体的名称。

通常,数据提供者是扩展 Provider 的 trait 的 trait 对象。用户将通过指定数据的类型从 trait 对象请求数据。

数据流

  • 用户请求特定类型的对象,该对象委托给 request_valuerequest_ref
  • request_* 创建一个 Demand 对象并将其传递给 Provider::provide
  • Provider::provide 的数据提供者实现尝试使用 Demand::provide_* 提供不同类型的值。如果类型与用户请求的类型匹配,则该值将存储在 Demand 对象中。
  • request_* 解包 Demand 对象并将任何存储的值返回给用户。

Examples

use std::any::{Provider, Demand, request_ref};

// MyTrait 的定义,一个数据提供者。
trait MyTrait: Provider {
    // ...
}

// `MyTrait` trait 对象的方法。
impl dyn MyTrait + '_ {
    /// 获取对实现结构体的字段的引用。
    pub fn get_context_by_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
        request_ref::<T>(self)
    }
}

// `MyTrait` 和 `Provider` 的下游实现。
impl MyTrait for SomeConcreteType {
    // ...
}

impl Provider for SomeConcreteType {
    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
        // 提供一个字符串引用。
        // 我们可以在这里提供不同类型的多个值。
        demand.provide_ref::<String>(&self.some_string);
    }
}

// `MyTrait` 的下游用法。
fn use_my_trait(obj: &dyn MyTrait) {
    // 向 obj 请求 &String。
    let _ = obj.get_context_by_ref::<String>().unwrap();
}
Run

在这个例子中,如果 use_my_traitobj 的具体类型是 SomeConcreteType,那么 get_context_by_ref 调用将返回一个引用给 &String 类型的 obj.some_string

Structs

  • DemandExperimental
    用于按类型提供数据的帮助器对象。
  • TypeId 代表类型的全局唯一标识符。

Traits

  • ProviderExperimental
    Trait 由可以根据类型动态提供值的类型实现。
  • 一个用来模拟动态类型的 trait。

Functions

  • request_refExperimental
    Provider 请求引用。
  • request_valueExperimental
    Provider 请求一个值。
  • type_name_of_valExperimental
    以字符串切片的形式返回指向的值的类型的名称。 这与 type_name::<T>() 相同,但是可以在不容易获得变量类型的地方使用。
  • 以字符串切片的形式返回类型的名称。