у меня такая установка
#[derive(Deserialize)]
struct GameData {
game: String,
player_data: Vec<MarioPartyData>,
<more common data>
}
#[derive(Deserialize)]
#[serde(untagged)]
enum MarioPartyData {
MarioParty(MarioParty),
MarioParty2(MarioParty2),
MarioParty3(MarioParty3),
<many more variants>
}
#[derive(Deserialize)]
struct MarioParty {
stars: i32,
coins: i32,
spaces_walked: i32
}
#[derive(Deserialize)]
struct MarioParty2 {
stars: i32,
coins: i32
}
#[derive(Deserialize)]
struct MarioParty3 {
stars: i32,
coins: i32
}
Это почти работает. Проблема в том, что некоторые игры имеют одинаковую структуру, поэтому, когда я десериализую MarioParty3, в данном случае он становится вариантом MarioParty2, потому что это первый вариант, которому он соответствует. Поле game должно однозначно определять, в какую игру нужно десериализовать, но я не могу понять, как использовать различные макросы тегов в serde для этого и возможно ли это вообще. Я надеюсь избежать реализации десериализатора самостоятельно. Также есть небольшая морщинка в том, что поле game будет не "MarioParty3", а скорее "Mario Party 3", хотя я думаю, что это можно было бы решить с помощью чего-то вроде #[serde(rename = "Mario Party 3")]?
Действительные входные данные JSON для экземпляра MarioParty3 могут выглядеть так:
{
"game": "Mario Party 3",
"player_data": [
{
"stars": 3,
"coins" 45
}
]
}
Я не против изменения каких-либо структур, которые у меня есть в rust, но вход JSON довольно устойчив. Любой совет приветствуется!

Самый простой способ представить этот JSON с помощью Serde — использовать перечисление со смежными тегами.
#[derive(Deserialize)]
struct GameData {
#[serde(flatten)]
player_data: MarioPartyData,
// <more common data>
}
#[derive(Deserialize)]
#[serde(tag = "game", content = "player_data")]
enum MarioPartyData {
#[serde(rename = "Mario Party")]
MarioParty(Vec<MarioParty>),
#[serde(rename = "Mario Party 2")]
MarioParty2(Vec<MarioParty2>),
#[serde(rename = "Mario Party 3")]
MarioParty3(Vec<MarioParty3>),
// <many more variants>
}
Это меняет структуру, так что Vec встречается внутри перечисления, заставляя каждый Vec содержать только один тип. Похоже, это хорошо отражает ваш JSON, но может изменить то, как вы с ним справляетесь в Rust.
Ах! Я не рассматривал возможность перемещения
Vecвнутри перечисления. Кажется, это работает! И на самом деле он лучше представляет данные: каждый экземпляр вVecдолжен относиться к одному и тому же варианту. Для потомков мне не было очевидно, что мне нужно удалить полеgameизGameData, чтобы это решение работало, но после этого это здорово! Спасибо!