Estou tentando gerar um objeto json como abaixo
// final json output expected
{
"j1": {
"1981": {
"income": 215
},
"1982": {
"income": 350
},
},
"j2": {
"1981": {
"income": 100
},
"1982": {
"income": 215
},
}
}
Eu tenho o seguinte código
use serde_json::{Value, Map};
struct s {
name: String,
year: i32,
income: i64
}
fn main() {
let rows :Vec<s> = vec!(
s { name: "j1".to_string(), year: 1981, income: 100},
s { name: "j1".to_string(), year: 1981, income: 115},
s { name: "j1".to_string(), year: 1982, income: 120},
s { name: "j1".to_string(), year: 1982, income: 100},
s { name: "j1".to_string(), year: 1982, income: 130},
s { name: "j2".to_string(), year: 1981, income: 100},
s { name: "j2".to_string(), year: 1982, income: 120},
s { name: "j2".to_string(), year: 1982, income: 130}
);
let mut data_map: Map<String, Value> = Map::new();
for row in rows {
let mut name: &Map<String, Value> = match data_map.get(&row.name) {
Some(val) => { &val.as_object().unwrap() },
None => { &Map::new() }
};
let mut year: &Map<String, Value> = match data_map.get(&row.year.to_string()) {
Some(val) => { &val.as_object().unwrap() },
None => { &Map::new() }
};
let income: i64 = year.get("income").unwrap_or(&Value::Number(0i64.into())).as_i64().unwrap() + row.income;
year.insert("income".to_string(), Value::Number(income.into()));
}
}
Criei este código para fazer a pergunta. Também consultei o deepseek e tal
A mensagem de erro que estou recebendo é
error[E0596]: cannot borrow `*year` as mutable, as it is behind a `&` reference
--> src\main.rs:32:9
|
32 | year.insert("income".to_string(), Value::Number(income.into()));
| ^^^^ `year` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
help: consider changing this binding's type
|
27 | let mut year: &mut serde_json::Map<std::string::String, Value> = match data_map.get(&row.year.to_string()) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Claramente tenho deficiência em entender referência e empréstimo. Qualquer ajuda seria apreciada.
Primeiro, você não costuma criar JSON manualmente. Você cria uma representação Rust dele e então deixa
serde_json
convertê-lo para JSON. Isso significa, não lide comValue
você mesmo.Claro que você também pode construir JSONs manualmente, mas isso raramente tem alguma vantagem sobre deixar
serde_json
fazer isso.Aqui está uma solução. Primeiro, precisamos das seguintes dependências em
Cargo.toml
:E aqui está o código:
Sobre o erro de empréstimo no seu código original: não tenho certeza de como ajudar você nisso. Há muitos erros aí, tanto problemas de propriedade quanto problemas lógicos.
Presumo que você pretende consultar um membro de
data_map
usando arow.name
chave e, se ela não existir, insira um novo mapa. Vejo que você cria um novo mapa, mas nunca o insere emdata_map
lugar nenhum. O resto dos problemas são um monte de&
coisas que estão erradas, às vezes porque os valores já são referências e, às vezes, porque são para variáveis que são temporárias e você cria referências pendentes.Eu adoraria dissecar seu código com mais detalhes e explicar os erros para você, mas é meio confuso fazer isso :D
Em vez disso, aqui vai uma reescrita. Talvez ajude seu entendimento:
Mas, novamente, não faça isso a menos que seja absolutamente necessário;
serde_json
não é realmente feito para ser usado dessa forma. UsarValue
diretamente só causa muitosas_<type>().unwrap()
casts, e não há nenhuma vantagem real sobre usar um tipo Rust que implementaserde::Serialize
. É assimserde_json
que deve ser usado; veja#[derive(Serialize)]
no meu primeiro exemplo. Recomendo ler serde.rs para mais informações.o que você está tentando alcançar não está claro:
No seu primeiro trecho de código (a saída JSON esperada), parece que você quer um objeto JSON com uma lista de objetos aninhados onde cada um tem um nome, por exemplo,
j1
correspondendo a uma lista de objetos com uma renda por ano.No entanto, esta não é uma maneira muito padrão de escrever JSON. Normalmente, você tem nomes de variáveis e valores separados por uma coluna
:
, e vários elementos do mesmo tipo são armazenados em um array, que é o que você faz no seu segundo trecho de código.Não entendo por que você está tentando usar um serde_json::Map aqui. Se você quiser apenas imprimir como uma string json seu
rows
objeto, você pode modificar seu código para o seguinte (certifique-se de adicionar o crate serde com o recurso derive executandocargo add serde --features=derive
)Você deverá ver o seguinte (após a formatação para multilinha):
Espero que isso ajude