2个版本
0.5.3 | 2024年2月22日 |
---|---|
0.5.2 | 2024年2月16日 |
1676 在 数据结构 中
每月下载量 57
280KB
187 行
field_accessor_pub
使用此过程宏,您可以通过一个字符串类型变量动态地获取和更新结构体的字段。当编译时不知道需要哪个字段时,这可能会很有用。功能类似于Python的 getattr
、setattr
。
安装
[dependencies]
field_accessor_pub = "0"
关于此宏的说明
此宏为结构体提供四种方法。仅对 get
、set
进行处理,以处理每个字段的类型,我定义了 GetterSetter<T>
trait 并为每种类型实现了它。
trait GetterSetter<T> {
fn get(&self, field_string: &String) -> Result<&T, String>;
fn set(&mut self, field_string: &String, value: T) -> Result<(), String>;
}
//implement for each type
impl GetterSetter<String> for StructName {
fn get(&self, field_string: &String) -> Result<&String, String>;
fn set(&mut self, field_string: &String, value: String) -> Result<(), String>;
}
impl GetterSetter<u32> for StructName {
fn get(&self, field_string: &String) -> Result<&u32, String>;
fn set(&mut self, field_string: &String, value: u32) -> Result<(), String>;
}
etc...
get
fn get(&self, field_string: &String) -> Result<&T, String>;
它返回一个字段的值。请注意,您需要指定返回类型。
get_mut
fn get_mut(&mut self, field_string: &String) -> Result<&mut T, String>;
返回对应于字段字符串的字的可变引用。
set
fn set(&mut self, field_string: &String, value: String) -> Result<(), String>;
它更新一个字段的值。
take
fn take(&mut self, field_string: &String) -> Result<T, String>;
将T的类型默认值替换为字段的值,并返回之前的字段值。
swap
fn swap(&mut self, field_string: &String, field_string_y: &String) -> Result<(), String>;
交换两个字段的值,而不初始化任何一个。
replace
fn replace(&mut self, field_string: &String, src: T) -> Result<T, String>;
将src移动到字段中,并返回之前的字段值。
getenum
fn getenum(&self, field_string: &String) -> Result<(StructName)FieldEnum, String>;
它像 get
方法一样返回字段的值,但返回类型是枚举。当字段类型不同时,此方法很有用。我将在后面解释枚举。
getstructinfo
fn getstructinfo(&self) -> (StructName)StructInfo;
您可以提取结构体的字段名称、类型和结构体名称。
使用方法和示例
use field_accessor_pub::FieldAccessor;
#[derive(FieldAccessor)]
struct Dog {
name: String,
age: u32,
life_expectancy: u32,
}
fn main() {
let mut dog = Dog {
name: "Taro".to_string(),
age: 3,
life_expectancy: 9,
};
let field_name = "name".to_string();
let value_to_update = "Jiro".to_string();
dog.set(&field_name, value_to_update).unwrap();
let value_on_error;
let fieldvalue: &String = match dog.get(&"invalid_field".to_string()) {
Ok(value) => value,
Err(_) => {value_on_error = "Ken".to_string(); &value_on_error},
};
println!("{:?}", fieldvalue);
let field_name = "age".to_string();
let value_to_update = 4u32;
dog.set(&field_name, value_to_update).unwrap();
let fieldvalue: &u32 = dog.get(&field_name).unwrap();
println!("{:?}", fieldvalue);
let field_name = "life_expectancy".to_string();
let value_to_update = 10u32;
dog.set(&field_name, value_to_update).unwrap();
let fieldvalue: &u32 = dog.get(&field_name).unwrap();
println!("{:?}", fieldvalue);
}
输出
"Ken"
4
10
此代码在编译时生成。
已知问题
您需要指定返回值的类型。如果没有给出,编译器无法推断类型。此限制降低了使用此宏的便利性。
#[derive(FieldAccessor)]
struct Dog {
name: String,
age: u32,
life_expectancy: u32,
}
let mut dog = Dog {
name: "Taro".to_string(),
age: 3,
life_expectancy: 9,
};
let fields = vec![
"name".to_string(),
"age".to_string(),
"life_expectancy".to_string(),
]
for field_name in fields.into_iter(){
let fieldvalue = dog.get(&field_name).unwrap();
};
此代码会引发错误。
let fieldvalue = dog.get(&field_name).unwrap();
---------- ^^^ cannot infer type for type parameter `T` declared on the trait `GetterSetter`
|
consider giving `fieldvalue` the explicit type `&T`, where the type parameter `T` is specified
一种解决方案是替换 get
为 getenum
。此宏在幕后为您定义了如下代码:(struct name)FieldEnum
。
enum DogFieldEnum {
name(String),
age(u32),
life_expectancy(u32),
}
您可以将此用作返回类型。使用此枚举,您可以在不关心字段类型的情况下获取任何字段的值。
let mut dog = Dog {
name: "Taro".to_string(),
age: 3,
life_expectancy: 9,
};
let fields = vec![
"name".to_string(),
"age".to_string(),
"life_expectancy".to_string(),
];
let mut fieldvalues: Vec<DogFieldEnum> = vec![];
for field_name in fields.into_iter(){
fieldvalues.push(dog.getenum(&field_name).unwrap());
};
assert_eq!(fieldvalues[0], DogFieldEnum::name("Taro".to_string()));
assert_eq!(fieldvalues[1], DogFieldEnum::age(3));
获取结构体信息
您可以通过调用 getstructinfo
使用 (字段名)StructInfo
获取结构体的信息。
(字段名)StructInfo
的定义
struct DogStructInfo {
field_names: Vec<String>,
field_types: Vec<String>,
struct_name: String
}
示例
let info = dog.getstructinfo();
println!("{:?}", info);
for i in info.field_names.iter() {
let fieldvalue: DogFieldEnum = dog.getenum(i).unwrap();
println!("{:?}", fieldvalue);
}
输出
DogStructInfo { field_names: ["name", "age", "life_expectancy"], field_types: ["String", "u32", "u32"], struct_name: "Dog" }
name("Jiro")
age(4)
life_expectancy(10)
作者
Tomohiro Endo ([email protected])
依赖项
~1.5MB
~35K SLoC