#struct-fields #field #access #struct #field-name #runtime-access #field-access

fieldname-access

通过名称在运行时安全地访问结构体字段的派生宏

2个版本

新版本 0.1.11 2024年8月22日
0.1.10 2024年7月15日

968过程宏

每月 38次下载

MIT/Apache

18KB
212

FieldnameAccess 派生宏

当不知道确切需要哪个字段时,我们可以根据其他数据匹配并执行一些操作,此时使用它可以安全地从结构体中通过字段名获取值

容器属性

  • #fieldname_enum(name = "NewName") - 生成可能值枚举的名称
use fieldname_access::FieldnameAccess;

#[derive(FieldnameAccess, Default)]
#[fieldname_enum(name = "NewName")]
struct NamedFieldname {
  name: String,
  age: i64,
}

let mut instance = NamedFieldname::default();
match instance.field("name").unwrap() {
    NewName::String(val) => {}
    NewName::I64(val) => {},
}
match instance.field_mut("name").unwrap() {
    NewNameMut::String(val) => {}
    NewNameMut::I64(val) => {},
}
  • #fieldname_enum(derive = [Debug, Clone], derive_mut = [Debug]) - 为生成的枚举生成派生宏。 derive 仅对不可变引用的枚举有效,derive_mut 仅对可变引用的枚举有效。当您只想对不可变引用派生 Clone 时,这可能很有用,因为可变引用不可克隆
use fieldname_access::FieldnameAccess;

#[derive(FieldnameAccess)]
#[fieldname_enum(derive = [Debug, Clone], derive_mut = [Debug])]
struct NamedFieldname {
  name: String,
  age: i64,
}
  • #fieldname_enum(derive_all = [Debug]) - 为不可变和可变生成的枚举生成派生宏
use fieldname_access::FieldnameAccess;

#[derive(FieldnameAccess)]
#[fieldname_enum(derive_all = [Debug])]
struct NamedFieldname {
  name: String,
  age: i64,
}

字段属性

  • #fieldname = "AmazingAge" - 生成枚举中字段变体的名称。当您想使用特定变体名称“标记”字段时,这可能很有用
use fieldname_access::FieldnameAccess;

#[derive(FieldnameAccess, Default)]
struct NamedFieldname {
  name: String,
  #[fieldname = "MyAge"]
  age: i64,
  dog_age: i64
}
let mut instance = NamedFieldname::default();
match instance.field("name").unwrap() {
    NamedFieldnameField::String(val) => {}
    NamedFieldnameField::MyAge(val) => {}
    NamedFieldnameField::I64(val) => {}
}
match instance.field_mut("name").unwrap() {
    NamedFieldnameFieldMut::String(val) => {}
    NamedFieldnameFieldMut::MyAge(val) => {}
    NamedFieldnameFieldMut::I64(val) => {}
}  

实际示例

假设我们有一个User结构体和针对它的Crit准则。

use fieldname_access::FieldnameAccess;

#[derive(FieldnameAccess)]
struct User {
    name: String,
    age: u64,
    does_love_ranni: bool, // important 
}

struct Crit {
    value: String,
    field: String,
    kind: CritKind,
}

enum CritKind {
    Contains,
    Equals,
    BiggerThan,
}

基于这些信息,FieldnameAccess 将生成所有可能的类型和为 User 结构体提供的方法,以便通过名称访问它们

enum UserField<'a> {
  String(&'a String),
  U64(&'a u64),
  Bool(&'a bool)
}

enum UserFieldMut<'a> {
  String(&'a mut String),
  U64(&'a mut u64),
  Bool(&'a mut bool)
}

有了这两个元素的信息,我们可以确定我们的下一步行动。

let user = User {
    age: 2022,
    name: String::from("Radahn"),
    does_love_ranni: true,
};

let crits = vec![
    Crit {
        value: String::from("Ra"),
        field: String::from("name"),
        kind: CritKind::Contains,
    },
    Crit {
        value: String::from("true"),
        field: String::from("does_love_ranni"), // important
        kind: CritKind::Equals,
    },
    Crit {
        value: String::from("18"),
        field: String::from("age"),
        kind: CritKind::BiggerThan,
    },
];

let its_ok = crits.into_iter().all(|crit| {
    let user_field =
        user.field(&crit.field).expect("Criteria has wrong fieldname");
    match crit.kind {
        CritKind::Contains => match user_field {
            UserField::String(str) => str.contains(&crit.value),
            _ => panic!("Criteria has wrong value"),
        },
        CritKind::Equals => match user_field {
            UserField::String(str) => str.eq(&crit.value),
            UserField::U64(int) => int.eq(&crit.value.parse::<u64>().unwrap()),
            UserField::Bool(boolean) => {
                boolean.eq(&crit.value.parse::<bool>().unwrap())
            }
        },
        CritKind::BiggerThan => match user_field {
            UserField::U64(int) => int > &crit.value.parse::<u64>().unwrap(),
            _ => panic!("Criteria has wrong value"),
        },
    }
});
assert!(its_ok);

您还可以修改字段

if let Some(UserFieldMut::Bool(does_love_ranni)) =
    user.field_mut("does_love_ranni") // important
{
    *does_love_ranni = false; // HARAM
}
assert!(!user.does_love_ranni); //important

依赖项

~2MB
~52K SLoC