#struct-fields #named-fields #name #larger #containing #listing #conversion

extruct

Extruct是一个proc-macro库,它提供列出命名结构体字段和实现包含具有相同名称字段的较大结构体的转换的工具。

2个发布版

0.1.1 2024年8月26日
0.1.0 2024年8月23日

540Rust模式

Download history 152/week @ 2024-08-18

每月152次下载

MIT许可证

12KB

extruct

Extruct

Extruct是一个proc-macro库,它提供列出命名结构体字段和实现包含具有相同名称字段的较大结构体的转换的工具。

描述

Extruct主要针对以下用例。
REST API通常在JSON响应中返回一个对象的大量属性。通常,作为API的用户,你只对其中的一些感兴趣,并不真的需要其他的。为了便于此,REST服务通常支持通过fields查询参数传递客户端感兴趣的属性列表。请参见此模式的示例这里这里
Extruct提供两个简单易用的过程宏,这在实现仅从后端检索特定属性的REST API包装器时可能很有用。

第一个宏是一个派生宏Fields。它适用于具有命名字段的结构体,并实现了返回字段名称字符串字面量的Fields特质。

第二个宏是一个属性宏extruct_from。当存在一个包含所有可能字段的“超级结构体”时,可以使用它。在这种情况下,当定义仅包含所有这些字段子集的自己的结构体时,可以使用extruct_from,它将实现将超级结构体实例转换为结构体实例的std::convert::From特质,通过将原始结构体中的所有字段转换为子结构体中具有相同名称的字段来实现。除了方便将“完整”对象转换为“部分”对象外,这还确保了所有字段都使用相同的名称,并且它们的类型是兼容的。

示例

#[derive(Fields)]
struct SuperStruct {
    one_field: String,
    another_field: u32,
    and_one_more: char,
}

#[derive(Fields)]
#[extruct_from(SuperStruct)]
struct SubStruct {
    and_one_more: String,
}

assert_eq!(SuperStruct::fields(), ["one_field", "another_field", "and_one_more"]);
assert_eq!(SubStruct::fields(), ["and_one_more"]);

let sup = SuperStruct {
    one_field: "str".to_owned(),
    another_field: 1135,
    and_one_more: 'x',
};

let sub: SubStruct = sup.into();
assert_eq!(sub.and_one_more, "x".to_owned());

注释

可以应用Fields派生宏到命名结构和单元结构,但无名结构只有当它是空的时候才能使用#[derive(Fields)]来注解。

extruct_from属性宏只能应用于非泛型的命名结构,并且只能引用一个具体的(非泛型)结构作为超结构。这个限制是因为宏无法看到超结构的定义,因此在实现std::convert::From特质时,无法指定泛型字段的特质界限。如果您想使用泛型结构的特定实例作为超结构,可以使用类型别名,如下所示

// A generic struct cannot be referenced by the extruct_from() attribute macro...
struct GenericStruct<T, S> {
    one_field: T,
    another_field: u32,
    and_one_more: S,
}

// ... but a non-generic type alias can be referenced by the extruct_from()
// attribute macro just fine
type ConcreteStruct = GenericStruct<String, char>;

#[extruct_from(ConcreteStruct)]
struct SubStruct {
    and_one_more: String,
}

let sup = ConcreteStruct {
    one_field: "str".to_owned(),
    another_field: 1135,
    and_one_more: 'x',
};

let sub: SubStruct = sup.into();
assert_eq!(sub.and_one_more, "x".to_owned());

依赖关系

~250–700KB
~17K SLoC