提问人:pielgrzym 提问时间:9/1/2023 更新时间:9/1/2023 访问量:125
使用 serde::from_value 反序列化为泛型类型
Deserialize into a generic type with 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
答:
4赞
Jmb
9/1/2023
#1
在函数中,需要指定类型是可反序列化的 ():get_result
T
T: for<'a> Deserialize<'a>
use serde::Deserialize;
use serde_json; // 1.0.102
#[derive(Deserialize)]
struct ApiResult<T> {
pub data: T,
pub status: String
}
fn get_result<T: for<'a> Deserialize<'a>>(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(())
}
评论
0赞
pielgrzym
9/1/2023
谢谢!!你能告诉我为什么会这样吗?我还没有见过语法 - 它是怎么称呼的?for
0赞
Jmb
9/1/2023
但请注意,HRTB 不是这里的关键问题。主要问题是添加了隐式边界,因此 中需要相同的边界。#[derive(Deserialize)]
T: Deserialize
get_bound
0赞
Jmb
9/1/2023
由于具有生存期参数,因此您需要特定的生存期(例如)或HRTB(基本上意味着“任何生存期”)。Deserialize
T: Deserialize<'static>
4赞
cafce25
9/1/2023
我认为在这种情况下,还有 DeserializeOwned
,它本质上是 HRTB 作为一种特征。
评论
T
serde::Deserialize
ApiResult<T>
Deserialize
get_result
get_result<T: for<'a> serde::Deserialize<'a>>(json: serde_json::Value) -> Result<ApiResult<T>, anyhow::Error>