Rust类型名称处理库tynm的使用,tynm提供高效的类型名称获取与转换功能

🪶 Tynm -- Type Name

返回类型名称,指定模块段数作为字符串。

使用

将以下内容添加到 Cargo.toml

tynm = "0.2.0"

在代码中:

#[rustfmt::skip]
assert_eq!(
    core::any::type_name::<Option<String>>(), "core::option::Option<alloc::string::String>"
);

#[rustfmt::skip]
let tuples = vec![
    (tynm::type_name::<Option<String>>(),    "Option<String>"),
    (tynm::type_namem::<Option<String>>(1),  "core::..::Option<alloc::..::String>"),
    (tynm::type_namen::<Option<String>>(1),  "..::option::Option<..::string::String>"),
    // 1 segment from most and least significant modules.
    (tynm::type_namemn::<rust_out::two::three::Struct>(1, 1), "rust_out::..::three::Struct"),
    // traits
    (tynm::type_name::<dyn core::fmt::Debug>(), "dyn Debug"),
];

tuples
    .iter()
    .for_each(|(left, right)| assert_eq!(left, right));

动机

Rust 1.38 中稳定的 core::any::type_name 函数返回带有所有模块段的完全限定类型名称。这在错误消息中可能难以阅读,特别是对于类型参数化的类型。

通常,简单的类型名称更易读,并且足以区分错误中引用的类型。

许可证

根据以下任一许可

  • Apache License, Version 2.0
  • MIT license

由您选择。

贡献

除非您明确声明,否则任何有意提交用于包含在作品中的贡献,如 Apache-2.0 许可证中所定义,应按照上述双重许可,没有任何附加条款或条件。

完整示例代码

use tynm;

fn main() {
    // 获取类型名称,不包含模块路径
    let type_name = tynm::type_name::<Option<String>>();
    assert_eq!(type_name, "Option<String>");
    
    // 获取类型名称,指定从最显著模块开始的段数
    let type_namem = tynm::type_namem::<Option<String>>(1);
    assert_eq!(type_namem, "core::..::Option<alloc::..::String>");
    
    // 获取类型名称,指定从最不显著模块开始的段数
    let type_namen = tynm::type_namen::<Option<String>>(1);
    assert_eq!(type_namen, "..::option::Option<..::string::String>");
    
    // 自定义结构体示例
    mod rust_out {
        pub mod two {
            pub mod three {
                pub struct Struct;
            }
        }
    }
    
    // 同时指定最显著和最不显著模块的段数
    let type_namemn = tynm::type_namemn::<rust_out::two::three::Struct>(1, 1);
    assert_eq!(type_namemn, "rust_out::..::three::Struct");
    
    // trait 对象类型名称
    let trait_name = tynm::type_name::<dyn core::fmt::Debug>();
    assert_eq!(trait_name, "dyn Debug");
    
    println!("所有类型名称测试通过!");
}

1 回复

Rust类型名称处理库tynm的使用

介绍

tynm是一个专门用于处理Rust类型名称的库,提供了高效的类型名称获取与转换功能。该库能够帮助开发者获取类型的字符串表示,支持自定义格式化选项,并且具有零开销的编译时类型名称处理能力。

主要特性

  • 获取类型的完整限定名称
  • 支持自定义名称格式化(简化路径、去除模块前缀等)
  • 编译时计算,零运行时开销
  • 支持泛型类型的名称处理

安装方法

在Cargo.toml中添加依赖:

[dependencies]
tynm = "0.2"

基本用法

获取类型名称

use tynm::type_name;

fn main() {
    let name = type_name::<i32>();
    println!("Type name: {}", name); // 输出: i32
    
    let vec_name = type_name::<Vec<String>>();
    println!("Generic type: {}", vec_name); // 输出: alloc::vec::Vec<alloc::string::String>
}

使用格式化选项

use tynm::{type_name, Formatting};

fn main() {
    // 获取简化名称(去除模块前缀)
    let simplified = type_name::<Vec<String>>()
        .format()
        .simplify();
    
    println!("Simplified: {}", simplified); // 输出: Vec<String>
    
    // 自定义格式化
    let formatted = type_name::<std::collections::HashMap<i32, String>>()
        .format()
        .simplify()
        .replace("std::collections::", "");
    
    println!("Formatted: {}", formatted); // 输出: HashMap<i32, String>
}

在泛型函数中使用

use tynm::type_name;

fn print_type<T>() {
    println!("Type: {}", type_name::<T>());
}

fn main() {
    print_type::<i32>();      // 输出: i32
    print_type::<Vec<f64>>(); // 输出: alloc::vec::Vec<f64>
}

处理复杂类型

use tynm::type_name;

struct MyStruct<T> {
    value: T,
}

impl<T> MyStruct<T> {
    fn type_name() -> String {
        type_name::<Self>().to_string()
    }
}

fn main() {
    println!("Custom struct: {}", MyStruct::<i32>::type_name());
    // 输出: my_crate::MyStruct<i32>
}

高级用法

缓存类型名称

use tynm::type_name;
use std::collections::HashMap;
use std::any::TypeId;

struct TypeRegistry {
    names: HashMap<TypeId, String>,
}

impl TypeRegistry {
    fn new() -> Self {
        Self {
            names: HashMap::new(),
        }
    }
    
    fn register<T: 'static>(&mut self) {
        let type_id = TypeId::of::<T>();
        let name = type_name::<T>().to_string();
        self.names.insert(type_id, name);
    }
    
    fn get_name(&self, type_id: &TypeId) -> Option<&String> {
        self.names.get(type_id)
    }
}

完整示例demo

// 完整示例:展示tynm库的各种用法
use tynm::{type_name, Formatting};
use std::collections::HashMap;
use std::any::TypeId;

// 自定义泛型结构体
struct MyGenericStruct<T, U> {
    field1: T,
    field2: U,
}

impl<T, U> MyGenericStruct<T, U> {
    // 获取类型名称的方法
    fn get_type_name() -> String {
        type_name::<Self>().format().simplify().to_string()
    }
}

// 类型注册器
struct TypeNameRegistry {
    registry: HashMap<TypeId, String>,
}

impl TypeNameRegistry {
    fn new() -> Self {
        Self {
            registry: HashMap::new(),
        }
    }
    
    // 注册类型
    fn register_type<T: 'static>(&mut self) {
        let type_id = TypeId::of::<T>();
        let type_name = type_name::<T>()
            .format()
            .simplify()
            .to_string();
        self.registry.insert(type_id, type_name);
    }
    
    // 获取类型名称
    fn get_type_name<T: 'static>(&self) -> Option<&String> {
        self.registry.get(&TypeId::of::<T>())
    }
}

fn main() {
    println!("=== 基本类型名称获取 ===");
    
    // 基本类型
    println!("i32: {}", type_name::<i32>());
    println!("String: {}", type_name::<String>());
    
    // 标准库类型
    println!("Vec<i32>: {}", type_name::<Vec<i32>>());
    println!("HashMap<String, i32>: {}", type_name::<HashMap<String, i32>>());
    
    println!("\n=== 格式化类型名称 ===");
    
    // 简化名称
    let simplified = type_name::<Vec<String>>()
        .format()
        .simplify();
    println!("简化后的Vec<String>: {}", simplified);
    
    // 自定义格式化
    let custom_formatted = type_name::<std::collections::HashMap<i32, String>>()
        .format()
        .simplify()
        .replace("std::collections::", "collections::");
    println!("自定义格式化: {}", custom_formatted);
    
    println!("\n=== 泛型函数中使用 ===");
    
    // 泛型函数
    fn print_generic_type<T>() {
        let name = type_name::<T>().format().simplify();
        println!("泛型类型: {}", name);
    }
    
    print_generic_type::<i32>();
    print_generic_type::<Vec<f64>>();
    print_generic_type::<HashMap<String, bool>>();
    
    println!("\n=== 自定义结构体类型名称 ===");
    
    // 自定义结构体
    println!("自定义泛型结构体: {}", MyGenericStruct::<i32, String>::get_type_name());
    
    println!("\n=== 类型注册器示例 ===");
    
    // 类型注册器使用
    let mut registry = TypeNameRegistry::new();
    
    // 注册各种类型
    registry.register_type::<i32>();
    registry.register_type::<String>();
    registry.register_type::<Vec<i32>>();
    registry.register_type::<HashMap<String, i32>>();
    registry.register_type::<MyGenericStruct<i32, String>>();
    
    // 获取注册的类型名称
    if let Some(name) = registry.get_type_name::<i32>() {
        println!("注册的i32类型: {}", name);
    }
    
    if let Some(name) = registry.get_type_name::<MyGenericStruct<i32, String>>() {
        println!("注册的自定义结构体类型: {}", name);
    }
    
    println!("\n=== 复杂类型处理 ===");
    
    // 嵌套泛型类型
    let complex_type = type_name::<Vec<HashMap<String, Option<i32>>>>()
        .format()
        .simplify();
    println!("复杂嵌套类型: {}", complex_type);
}

// 单元测试
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_basic_type_names() {
        assert_eq!(type_name::<i32>().to_string(), "i32");
        assert_eq!(type_name::<String>().to_string(), "alloc::string::String");
    }
    
    #[test]
    fn test_formatting() {
        let simplified = type_name::<Vec<i32>>()
            .format()
            .simplify()
            .to_string();
        assert_eq!(simplified, "Vec<i32>");
    }
}

注意事项

  1. 类型名称的格式可能因Rust版本而异
  2. 调试构建和发布构建可能产生不同的类型名称字符串
  3. 对于复杂泛型类型,名称可能包含编译器内部表示

性能特点

  • 编译时计算,运行时零开销
  • 字符串在编译时生成并存储在静态内存中
  • 适合用于日志、调试信息、序列化等场景

这个库为需要处理类型名称的Rust开发者提供了简单而强大的工具,特别是在需要动态类型信息或生成调试输出的场景中非常有用。

回到顶部