多年前,作者在 Rust 中重新实现 Python 代码,需将 Python 的动态能力(__getattr__
)适配到 Rust 的严格编译世界。借助serde
序列化箱,作者开始尝试。文中以获取系统中安装的物理风扇信息为例,展示 Python 擅长用清晰、简洁且直观的接口抽象复杂实现,而 Rust 则不同。
抽象对象
用纯 Rust 表达“原始”API,有Value
和Object
两种类型,Object
可获取命名属性(Value
实例),但用户使用较痛苦,需手动检查Value
枚举变体。
设计思路
受 Pythonic API 启发,可让用户定义查询对象的自定义结构体,指定query
返回该结构体实例,类似let res: Vec<Fan> = api::query();
。但如何实现此功能需考虑使用的底层 API 和泛型返回类型等。
逐步改进
先定义新特质Queryable
,包含获取对象名和从Object
构建实例的方法,让query
函数能返回特定类型实例,用户只需为新类型实现该特质。但此方法繁琐易错,可借助serde
,它能生成Deserialize
实现,让用户只需添加derive(Deserialize)
即可。
Serde 救援
Serde 是 Rust 中序列化和反序列化数据的框架,通过derive
可生成Deserialize
实现。以Fan
结构体为例,使用serde_json
进行反序列化,只需添加#[derive(Debug, Deserialize)]
和相关配置。利用 Serde 可假装为另一种数据格式,创建接受实现Deserialize
的结构体的query
函数,方便用户。
深入探究
要使用Deserialize
trait,需了解其内部原理。手动实现Deserialize
时,需定义新的实用结构体和实现相关特质,如FanVisitor
,它通过visit_map
处理从反序列化器获取的数据,确定如何构建Fan
结构体。
实现反序列化器
使用Deserialize
的原因是其可由 Serde 为用户类型derive
,更新query
函数以使用DeserializeOwned
,引入新的中间结构体ObjectDeserializer
和特质T::deserialize(ObjectDeserializer { obj })
,以解耦反序列化器和用户的T
。实现ObjectDeserializer
的deserialize_struct
方法时,需定义实现serde::de::MapAccess
的新结构体ObjectMapAccess
,并在其中实现next_key_seed
和next_value_seed
函数,处理获取字段名和值的逻辑。
总结
最终流程为用户调用query
函数传入实现Deserialize
的T
,query
获取对象并调用T::Deserialize
,通过一系列步骤构建T
的实例。文中还提到可探索的其他替代方案和未来工作,如嵌套对象支持、新类型支持等,并展示了如何获取T
的名称等。总之,通过 Rust 的 trait 系统和 Serde 的特性,可构建有趣且便捷的 API。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。