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>");
}
}
注意事项
- 类型名称的格式可能因Rust版本而异
- 调试构建和发布构建可能产生不同的类型名称字符串
- 对于复杂泛型类型,名称可能包含编译器内部表示
性能特点
- 编译时计算,运行时零开销
- 字符串在编译时生成并存储在静态内存中
- 适合用于日志、调试信息、序列化等场景
这个库为需要处理类型名称的Rust开发者提供了简单而强大的工具,特别是在需要动态类型信息或生成调试输出的场景中非常有用。