10个版本 (4个破坏性版本)
0.5.2 | 2022年8月29日 |
---|---|
0.5.1 | 2022年5月10日 |
0.4.3 | 2022年5月8日 |
0.3.0 | 2022年5月5日 |
0.1.0 | 2022年5月4日 |
#20 在 #setter
每月69次下载
被 2 crate 使用
280KB
185 行
field_accessor
通过这个过程宏,你可以通过一个 String
类型的变量动态地获取和更新结构体的字段。如果你在编译时不知道想要哪个字段,它对你来说可能很有用。这个功能与Python的 getattr
和 setattr
类似。
安装
[dependencies]
field_accessor = "0"
关于此宏
此宏为结构体提供了四种方法。仅对 get
和 set
,为了处理每个字段的类型,我定义了 GetterSetter<T>
特性并为每种类型实现了它。
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>;
返回对应于 field_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::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
一种解决方法是使用 getenum
替换 get
。此宏在幕后为你定义了 (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