Skip to content

TypeRegistry

derive(Reflect) 让类型有了反射能力,但光有能力还不够——引擎需要一个中央目录来管理所有反射类型的元信息。这就是 TypeRegistry:按 TypeId 或类型路径字符串查找注册信息,拿回 TypeRegistration 对象,从中读取 TypeInfo 和附加的 TypeData

创建与注册

rust
#[derive(Reflect, Default)]
#[reflect(Default)]
struct Score {
    value: u32,
    combo: u8,
}

#[derive(Reflect)]
struct Enemy {
    name: String,
    hp: i32,
}
rust
let mut registry = TypeRegistry::default();
    registry.register::<Score>();
    registry.register::<Enemy>();

TypeRegistry::new() 会预注册所有基本类型(booli32f32String 等);TypeRegistry::default() 等价。register::<T>() 把你的自定义类型加进去——它会递归注册字段类型(比如 Scoreu32u8),并把 #[reflect(...)] 声明的 TypeData 一并录入。重复注册同一类型不会覆盖。

按 TypeId 查找

rust
let score_id = std::any::TypeId::of::<Score>();
    let registration = registry.get(score_id).unwrap();
    println!("TypePath: {}", registration.type_info().type_path());
    println!("ShortPath: {}", registration.type_info().type_path_table().short_path());

registry.get(TypeId) 返回 Option<&TypeRegistration>TypeRegistration 持有该类型的 TypeInfo——包括类型路径、字段信息、种类(Struct/Enum/Opaque 等)。

按字符串路径查找

当你只有类型名字符串(比如从场景文件读到的 "my_game::Player"),用 get_with_type_path

rust
let found = registry.get_with_type_path("listing_31_02::Enemy");
    assert!(found.is_some());
    println!("按路径找到: {}", found.unwrap().type_info().type_path());

注册时会自动索引完整路径和短名。短名(如 "Player")如果有歧义(两个模块都叫 Player),查找会返回 None——必须用完整路径。这是避免静默错误的安全设计。

TypeData 机制

TypeData 是附加在类型注册信息上的运行时元数据#[reflect(Default)] 注册的是 ReflectDefault#[reflect(Component)] 注册的是 ReflectComponent。它们都是 TypeData trait 的实现者。

rust
let score_reg = registry.get(std::any::TypeId::of::<Score>()).unwrap();
    let reflect_default = score_reg.data::<ReflectDefault>();
    println!("Score 有 ReflectDefault: {}", reflect_default.is_some());

registration.data::<ReflectDefault>() 返回 Option<&ReflectDefault>。如果有值,你就能通过它在运行时调用 Default::default() 创建实例——即使你手头只有 dyn PartialReflect,不知道具体类型。

你也可以手动注册 TypeData:

rust
registry.register_type_data::<MyType, ReflectSerialize>();

这在泛型类型上特别有用——泛型的 derive 无法在编译期确定所有具体参数,需要你在知道具体类型后手动补注册。

AppTypeRegistry 资源

在 Bevy 应用里,TypeRegistry 不是裸着用的——引擎把它包在 AppTypeRegistry 资源里,DefaultPlugins 会自动创建它。你的游戏类型需要在 startup 系统里注册:

rust
fn register_types(registry: Res<AppTypeRegistry>) {
    let mut registry = registry.write();
    registry.register::<Player>();
    registry.register::<Enemy>();
}

AppTypeRegistry 内部是 TypeRegistryArcArc<RwLock<TypeRegistry>>),所以可以安全地跨系统共享。Scene 加载、Inspector 面板、BRP 远程协议都是通过读这个资源来获取类型信息的。

运行:

console
cargo run -p ch31-reflect --example listing-31-02

下一节看拿到类型信息后,怎么在运行时真正读写字段。