Rust属性宏库into-attr-derive的使用:简化类型转换与属性派生
Rust属性宏库into-attr-derive的使用:简化类型转换与属性派生
安装
在项目目录中运行以下Cargo命令:
cargo add into-attr-derive
或者在Cargo.toml中添加以下行:
into-attr-derive = "0.2.1"
示例代码
下面是两个完整示例,展示如何使用into-attr-derive
库:
基础示例
use into_attr_derive::IntoAttr;
// 定义简单结构体
#[derive(IntoAttr)]
struct Person {
name: String,
age: u32,
}
fn main() {
// 创建实例
let person = Person {
name: "Alice".to_string(),
age: 30,
};
// 转换为属性
let attrs = person.into_attr();
// 使用转换后的属性
println!("Name: {}", attrs.name);
println!("Age: {}", attrs.age);
}
高级示例
use into_attr_derive::IntoAttr;
// 嵌套结构体
#[derive(IntoAttr, Debug, Clone)]
struct Address {
street: String,
city: String,
zip: String,
}
// 主结构体
#[derive(IntoAttr)]
struct Employee {
id: u64,
#[into_attr(skip)] // 跳过该字段
salary: f64,
address: Address, // 嵌套结构体
}
fn main() {
// 创建地址实例
let address = Address {
street: "123 Main St".to_string(),
city: "Metropolis".to_string(),
zip: "12345".to_string(),
};
// 创建员工实例
let employee = Employee {
id: 42,
salary: 75000.0,
address: address.clone(),
};
// 转换为属性
let attrs = employee.into_attr();
// 输出结果
println!("Employee ID: {}", attrs.id);
println!("Address: {:?}", attrs.address);
}
工作原理
这个库通过属性宏自动为结构体实现类型转换,主要功能包括:
- 自动生成
into_attr
方法 - 保留字段原始类型
- 支持嵌套结构体转换
- 保持所有权语义
注意事项
- 使用非标准许可证
- 当前版本为0.2.1
- 维护者:Boris Zhguchev
1 回复
Rust属性宏库into-attr-derive的使用:简化类型转换与属性派生
into-attr-derive
是一个Rust属性宏库,旨在简化类型转换和属性派生的过程。它通过提供自定义派生宏来减少样板代码,使类型转换更加直观和类型安全。
主要功能
- 自动派生
Into
和From
trait实现 - 简化结构体之间的转换
- 支持属性配置来定制转换行为
安装
在Cargo.toml
中添加依赖:
[dependencies]
into-attr-derive = "0.1"
基本使用
简单类型转换
use into_attr_derive::IntoAttr;
#[derive(IntoAttr)]
struct User {
name: String,
age: u32,
}
#[derive(IntoAttr)]
struct UserDto {
name: String,
age: u32,
}
fn main() {
let user = User {
name: "Alice".to_string(),
age: 30,
};
// 自动获得Into<UserDto>实现
let user_dto: UserDto = user.into();
println!("Name: {}, Age: {}", user_dto.name, user_dto.age);
}
自定义字段映射
use into_attr_derive::IntoAttr;
#[derive(IntoAttr)]
struct Person {
first_name: String,
last_name: String,
#[into_attr(rename = "years")]
age: u32,
}
#[derive(IntoAttr)]
#[into_attr(for = "Person")]
struct PersonView {
full_name: String,
years: u32,
}
impl From<Person] for PersonView {
fn from(person: Person) -> Self {
PersonView {
full_name: format!("{} {}", person.first_name, person.last_name),
years: person.age,
}
}
}
fn main() {
let person = Person {
first_name: "John".to_string(),
last_name: "Doe".to_string(),
age: 42,
};
let view: PersonView = person.into();
println!("{} is {} years old", view.full_name, view.years);
}
高级用法
忽略字段
use into_attr_derive::IntoAttr;
#[derive(IntoAttr)]
struct Source {
id: u64,
name: String,
#[into_attr(skip)]
password: String,
}
#[derive(IntoAttr)]
struct Target {
id: u64,
name: String,
}
fn main() {
let source = Source {
id: 1,
name: "admin".to_string(),
password: "secret".to_string(),
};
let target: Target = source.into();
// password字段被自动忽略
}
自定义转换逻辑
use into_attr_derive::IntoAttr;
#[derive(IntoAttr)]
struct Celsius(f64);
#[derive(IntoAttr)]
#[into_attr(from = "Celsius")]
struct Fahrenheit(f64);
impl From<Celsius> for Fahrenheit {
fn from(c: Celsius) -> Self {
Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
}
}
fn main() {
let boiling = Celsius(100.0);
let boiling_f: Fahrenheit = boiling.into();
println!("Water boils at {}°F", boiling_f.0);
}
属性配置选项
#[into_attr(rename = "new_name")]
- 重命名字段#[into_attr(skip)]
- 跳过字段转换#[into_attr(default)]
- 使用默认值#[into_attr(from = "SourceType")]
- 指定源类型#[into_attr(for = "TargetType")]
- 指定目标类型
注意事项
- 结构体字段名称和类型需要匹配才能自动转换
- 对于复杂转换,仍然需要手动实现
From
trait - 宏展开后的代码可以使用
cargo expand
查看
into-attr-derive
库通过减少样板代码,使类型转换更加简洁和安全,特别适合在DTO(Data Transfer Object)模式或API边界类型转换中使用。
完整示例Demo
下面是一个结合多种功能的完整示例:
use into_attr_derive::IntoAttr;
// 源数据结构
#[derive(IntoAttr)]
struct Employee {
employee_id: u64,
first_name: String,
last_name: String,
#[into_attr(rename = "age")]
years_of_service: u8,
#[into_attr(skip)]
salary: f64,
department: String,
}
// 目标数据结构
#[derive(IntoAttr)]
#[into_attr(for = "Employee")]
struct EmployeeProfile {
id: u64,
full_name: String,
age: u8,
dept: String,
#[into_attr(default = "false")]
is_manager: bool,
}
// 自定义转换逻辑
impl From<Employee> for EmployeeProfile {
fn from(emp: Employee) -> Self {
EmployeeProfile {
id: emp.employee_id,
full_name: format!("{} {}", emp.first_name, emp.last_name),
age: emp.years_of_service,
dept: emp.department,
is_manager: false, // 默认值会被覆盖
}
}
}
fn main() {
let employee = Employee {
employee_id: 1001,
first_name: "张".to_string(),
last_name: "三".to_string(),
years_of_service: 5,
salary: 50000.0,
department: "IT".to_string(),
};
// 自动转换
let profile: EmployeeProfile = employee.into();
println!("员工档案:");
println!("ID: {}", profile.id);
println!("姓名: {}", profile.full_name);
println!("年龄: {}", profile.age);
println!("部门: {}", profile.dept);
println!("经理: {}", profile.is_manager);
}
这个完整示例展示了:
- 基本字段自动映射
- 字段重命名(
years_of_service
->age
) - 跳过敏感字段(
salary
) - 设置默认值(
is_manager
) - 自定义转换逻辑(组合
full_name
)
输出结果将是:
员工档案:
ID: 1001
姓名: 张 三
年龄: 5
部门: IT
经理: false