Rust点路径访问serde反序列化结构体时类型不匹配报错解决
问题描述
基础定义
将反序列化得到的JSON数据映射为Rust结构体,示例JSON与对应结构体定义如下:
示例JSON:
{ "infos": { "info_example": { "title": { "en": "Title for example", "fr": "Titre pour l'exemple" }, "message": { "en": "Message for example" } } }, "errors": {} }
对应Rust结构体定义(基于serde实现反序列化):
#[derive(Debug, Deserialize)] struct Logs { infos: Infos, errors: Errors, } #[derive(Debug, Deserialize)] struct Infos { info_example: Log, } #[derive(Debug, Deserialize)] struct Errors {} #[derive(Debug, Deserialize)] struct Log { title: MultiString, message: MultiString, } #[derive(Debug, Deserialize)] struct MultiString { en: String, fr: Option<String>, de: Option<String> }
目标功能
期望实现一个支持点分隔路径字符串访问任意嵌套字段的方法,调用形式如下:
logs_manager.get("infos.info_example.message.en")
初始实现与报错
初始编写的LogsManager代码如下:
struct LogsManager { logs: Logs } impl LogsManager { fn get<T>(&self, element: &str) -> &T { let splitted: Vec<&str> = element.split(".").collect(); // 后续将改为循环遍历完整路径,当前仅处理路径第一段做测试 match splitted[0] { "infos" => { &self.logs.infos }, "errors" => { &self.logs.errors } _ => panic!() } } }
编译时触发E0308类型不匹配错误:
Compiling so_question_return_type v0.1.0 (/run/media/anton/data120/Documents/testa) error[E0308]: mismatched types --> src/main.rs:26:17 | 20 | fn get<T>(&self, element: &str) -> &T { | - this type parameter -- expected `&T` because of return type ... 26 | &self.logs.infos | ^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `Infos` | = note: expected reference `&T` found reference `&Infos` error[E0308]: mismatched types --> src/main.rs:29:17 | 20 | fn get<T>(&self, element: &str) -> &T { | - this type parameter -- expected `&T` because of return type ... 29 | &self.logs.errors | ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `Errors` | = note: expected reference `&T` found reference `&Errors` For more information about this error, try `rustc --explain E0308`. error: could not compile `so_question_return_type` due to 2 previous errors
尝试的解决方案与新问题
为解决返回类型不统一的问题,尝试定义枚举包装所有可能的返回类型:
enum LogObject<'a> { Logs(&'a Logs), Infos(&'a Infos), Errors(&'a Errors), Log(&'a Log), MultiString(&'a MultiString) }
将返回对象包装为LogObject枚举变体后代码可以通过编译,示例代码如下:
"infos" => { LogObject::Infos(&self.logs.infos) }
为了便捷取出枚举中包装的内部对象,尝试实现泛型取值方法:
impl<'a> LogObject<'a> { fn retrieve_object<T>(&self) -> &T { match *self { Self::Logs(object) => object, Self::Infos(object) => object, Self::Errors(object) => object, Self::Log(object) => object, Self::MultiString(object) => object, } } }
该实现再次触发编译错误:
error[E0308]: mismatched types --> crates/strings/src/manager.rs:63:44 | 61 | fn retrieve_object<T>(&self) -> &T { | - -- expected `&T` because of return type | | | this type parameter 62 | match *self { 63 | Self::Logs(object) => object, | ^^^^^^ expected type parameter `T`, found struct `structured::Logs` | = note: expected reference `&T` found reference `&structured::Logs` For more information about this error, try `rustc --explain E0308`. error: could not compile `strings` due to previous error
尝试多种方案均无法解决问题,现咨询可行的实现方式。
内容的提问来源于stack exchange,提问作者antoninhrlt
相关产品推荐
相关产品推荐

