如何用serde::from_value反序列化泛型结构体?
问题:泛型结构体反序列化编译失败
尝试将API的JSON响应反序列化为泛型结构体,但代码无法编译,原代码如下:
use serde::Deserialize; use serde_json; // 1.0.102 #[derive(Deserialize)] struct ApiResult<T> { pub data: T, pub status: String } fn get_result<T>(json: serde_json::Value) -> Result<ApiResult<T>, anyhow::Error> { let r: ApiResult<T> = serde_json::from_value(json)?; Ok(r) } fn main() -> Result<(),anyhow::Error> { let json = serde_json::json!({ "data": 1, "status": "ok" }); let r2: ApiResult<i64> = get_result::<i64>(json).unwrap(); Ok(()) }
编译时出现以下错误:
Compiling playground v0.0.1 (/playground) error[E0277]: the trait bound `T: Deserialize<'_>` is not satisfied --> src/main.rs:11:27 | 11 | let r: ApiResult<T> = serde_json::from_value(json)?; | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `T` | note: required for `ApiResult<T>` to implement `for<'de> Deserialize<'de>` --> src/main.rs:4:10 | 4 | #[derive(Deserialize)] | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro 5 | struct ApiResult<T> { | ^^^^^^^^^^^^ = note: required for `ApiResult<T>` to implement `DeserializeOwned` note: required by a bound in `from_value` --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.102/src/value/mod.rs:983:8 | 981 | pub fn from_value<T>(value: Value) -> Result<T, Error> | ---------- required by a bound in this function 982 | where 983 | T: DeserializeOwned, | ^^^^^^^^^^^^^^^^ required by this bound in `from_value` = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 10 | fn get_result<T: _::_serde::Deserialize<'_>>(json: serde_json::Value) -> Result<ApiResult<T>, anyhow::Error> { | ++++++++++++++++++++++++++++ For more information about this error, try `rustc --explain E0277`. error: could not compile `playground` (bin "playground") due to previous error
修复方案
错误核心是get_result函数的泛型参数T缺少必要的 trait 约束:
serde_json::from_value要求目标类型实现DeserializeOwned,而ApiResult<T>要满足这个 trait,其内部的T必须支持反序列化(即实现for<'de> Deserialize<'de>)。
只需给get_result的泛型T添加约束即可修复,有两种等价写法:
写法一:使用DeserializeOwned约束
use serde::Deserialize; use serde_json; // 1.0.102 use serde::de::DeserializeOwned; #[derive(Deserialize)] struct ApiResult<T> { pub data: T, pub status: String } // 添加DeserializeOwned约束 fn get_result<T: DeserializeOwned>(json: serde_json::Value) -> Result<ApiResult<T>, anyhow::Error> { let r: ApiResult<T> = serde_json::from_value(json)?; Ok(r) } fn main() -> Result<(),anyhow::Error> { let json = serde_json::json!({ "data": 1, "status": "ok" }); let r2: ApiResult<i64> = get_result::<i64>(json).unwrap(); Ok(()) }
写法二:直接使用生命周期约束
use serde::Deserialize; use serde_json; // 1.0.102 #[derive(Deserialize)] struct ApiResult<T> { pub data: T, pub status: String } // 添加for<'de> Deserialize<'de>约束 fn get_result<T: for<'de> Deserialize<'de>>(json: serde_json::Value) -> Result<ApiResult<T>, anyhow::Error> { let r: ApiResult<T> = serde_json::from_value(json)?; Ok(r) } fn main() -> Result<(),anyhow::Error> { let json = serde_json::json!({ "data": 1, "status": "ok" }); let r2: ApiResult<i64> = get_result::<i64>(json).unwrap(); Ok(()) }
两种写法都能告诉编译器:T类型必须支持反序列化,从而让ApiResult<T>满足from_value的类型要求。
内容的提问来源于stack exchange,提问作者pielgrzym
相关产品推荐
相关产品推荐

