#getter-setter #struct-fields #proc-macro #setter #getter #setattr #getattr

field_accessor_pub

这是一个过程宏,用于动态地通过字符串获取和设置结构体字段。这个crate是field_accessor_pub的快速而简陋的分支。

2个版本

0.5.3 2024年2月22日
0.5.2 2024年2月16日

1676数据结构

Download history 45/week @ 2024-03-10 50/week @ 2024-03-17 3/week @ 2024-03-24 37/week @ 2024-03-31 6/week @ 2024-04-07 17/week @ 2024-04-14 20/week @ 2024-04-21

每月下载量 57

MIT 协议

280KB
187

field_accessor_pub

使用此过程宏,您可以通过一个字符串类型变量动态地获取和更新结构体的字段。当编译时不知道需要哪个字段时,这可能会很有用。功能类似于Python的 getattrsetattr

安装

[dependencies]
field_accessor_pub = "0"

关于此宏的说明

此宏为结构体提供四种方法。仅对 getset 进行处理,以处理每个字段的类型,我定义了 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;

您可以提取结构体的字段名称、类型和结构体名称。

使用方法和示例

run

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

一种解决方案是替换 getgetenum。此宏在幕后为您定义了如下代码:(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