[英]Skip invalid elements in a sequence with Serde deserialization
使用 Serde,我想通過保留有效元素並跳過無效元素來反序列化一系列元素。
我有以下有效載荷:
{
"nhits": 30,
"parameters": {
"dataset": "occupation-parkings-temps-reel",
"timezone": "UTC",
"rows": 50,
"start": 0,
"format": "json",
"facet": [
"etat_descriptif"
]
},
"records": [
{
"datasetid": "occupation-parkings-temps-reel",
"recordid": "1436c55a76fc7910b5a0336eb74cc0957870a8fd",
"fields": {
"nom_parking": "P1 Esplanade - Centre commercial",
"etat": 1,
"ident": 27,
"infousager": "220",
"idsurfs": "1703_DEP_27",
"libre": 229,
"total": 251,
"etat_descriptif": "Ouvert"
},
"record_timestamp": "2020-12-20T12:51:00.704000+00:00"
},
{
"datasetid": "occupation-parkings-temps-reel",
"recordid": "2b15689c04478fcad8c964a5d9f3c0148eb70126",
"fields": {
"etat": 1,
"ident": 30,
"infousager": "LIBRE",
"libre": 719,
"total": 719,
"etat_descriptif": "Ouvert"
},
"record_timestamp": "2020-12-20T12:51:00.704000+00:00"
}
],
"facet_groups": [
{
"facets": [
{
"count": 28,
"path": "Ouvert",
"state": "displayed",
"name": "Ouvert"
},
{
"count": 1,
"path": "Ferm\u00e9",
"state": "displayed",
"name": "Ferm\u00e9"
},
{
"count": 1,
"path": "frequentation temps reel indisponible",
"state": "displayed",
"name": "frequentation temps reel indisponible"
}
],
"name": "etat_descriptif"
}
]
}
我有一個不同的結構對應:
/// The container for the API response
#[derive(Debug, Deserialize)]
pub struct OpenDataResponse<T> {
/// The parameters relative to the response
pub parameters: Parameters,
/// The parameters relative to the pagination
#[serde(flatten)]
pub pagination: Pagination,
/// The sets of records inside the response
#[serde(bound(deserialize = "T: Deserialize<'de>"))]
#[serde(deserialize_with = "deserialize::failable_records")]
pub records: Vec<Record<T>>,
}
/// A record represents an item of some data
/// with a specific id.
#[derive(Debug, Deserialize)]
pub struct Record<T> {
/// The identifier of the record
#[serde(rename(deserialize = "recordid"))]
pub id: String,
#[serde(rename(deserialize = "fields"))]
pub(crate) inner: T,
}
#[derive(Debug, Deserialize)]
pub struct StatusOpenData {
#[serde(rename(deserialize = "idsurfs"))]
pub id: String,
#[serde(rename(deserialize = "nom_parking"))]
pub name: String,
#[serde(rename(deserialize = "etat"))]
pub status: i8,
#[serde(rename(deserialize = "libre"))]
pub free: u16,
pub total: u16,
#[serde(rename(deserialize = "etat_descriptif"))]
pub users_info: Option<String>,
}
關於這些定義, StatusOpenData
元素有一些必填字段。 所以在
示例中的records
,第一個元素有效,第二個元素無效。
我將自己的反序列化方法deserialize::failable_records
為:
struct FailableDeserialize<T> {
inner: Option<T>,
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for FailableDeserialize<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value: Option<T> = Deserialize::deserialize(deserializer).ok();
Ok(FailableDeserialize { inner: value })
}
}
pub(super) fn failable_records<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
// Error returned from the line below
let elements: Vec<FailableDeserialize<T>> = Deserialize::deserialize(deserializer)?;
let result = elements.into_iter().filter_map(|f| f.inner).collect();
Ok(result)
}
這失敗了一些錯誤,例如: should take errors into account: Error("expected
, or
] ",
我不明白為什么會返回錯誤: let elements: Vec<FailableDeserialize<T>> = Deserialize::deserialize(deserializer)?;
嘗試反序列化一系列FailableDeserialize<T>
元素,但這種類型以無法返回錯誤的方式實現Deserialize
。
我哪里錯了?
使用ok()
忽略錯誤的直接方法將導致解串器不同步。 反序列化錯誤可能發生在任何令牌上,並且不需要僅在消耗完整元素后發生。 如果反序列化Record
失敗,serde 將卡在Record
對象內,但Vec
反序列化器期望 a ,
它不會找到。
如果您堅持使用已經提供諸如FailableDeserialize
類的東西的現有板條箱,那就更容易了。 您可以使用serde_with::DefaultOnError
failable_records
像這樣編寫failable_records
:
fn failable_records<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
#[serde_with::serde_as]
#[derive(Deserialize)]
#[serde(bound(deserialize = "T: Deserialize<'de>"))]
struct Wrapper<T>(#[serde_as(deserialize_as = "Vec<serde_with::DefaultOnError>")] Vec<Option<T>>);
// Error returned from the line below
let elements: Wrapper<T> = Deserialize::deserialize(deserializer)?;
let result = elements.0.into_iter().filter_map(|f| f).collect();
Ok(result)
}
在內部,它使用未標記的枚舉來解決去同步問題,因為這將在開始真正的反序列化之前消耗一個完整的對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.