Introdução: por que JSON é importante em Rust
\n\nJSON (JavaScript Object Notation) é um formato leve de troca de dados que se tornou o padrão de facto para APIs web, arquivos de configuração e comunicação entre serviços. Em Rust, uma linguagem de programação de sistemas focada em segurança e desempenho, o trabalho com JSON é implementado através de um poderoso ecossistema de crates (bibliotecas).
\n\nApesar de Rust não ter suporte nativo a JSON (ao contrário de JavaScript ou Python), seu sistema de tipos e abordagem ao gerenciamento de memória tornam o processamento de JSON não apenas seguro, mas também incrivelmente rápido. Neste artigo, vamos abordar como fazer parsing de JSON para estruturas Rust, como serializar dados de volta para JSON e como evitar erros comuns de iniciantes.
\n\nA principal ferramenta para trabalhar com JSON em Rust é o crate serde (Serialization/Deserialization framework) em conjunto com serde_json. Essas bibliotecas fornecem abstrações de custo zero (zero-cost abstractions) e suportam estruturas de dados aninhadas complexas.
Instalação e configuração de dependências
\n\nAntes de começar, crie um novo projeto Rust e adicione as dependências necessárias no arquivo Cargo.toml:
[dependencies]\nserde = { version = "1.0", features = ["derive"] }\nserde_json = "1.0"\n\nA flag features = ["derive"] para o crate serde permite usar as macros #[derive(Serialize, Deserialize)], que geram automaticamente o código para converter suas estruturas para JSON e vice-versa. Esta é uma característica chave do Rust — você escreve o mínimo de código boilerplate, e o compilador cuida do trabalho rotineiro.
Após adicionar as dependências, execute cargo build para baixar e compilar as bibliotecas.
Parsing de JSON para estruturas Rust (desserialização)
\n\nCriação do modelo de dados
\n\nA primeira coisa a fazer é definir as estruturas Rust que correspondem aos seus dados JSON. Suponha que temos um JSON representando informações de um usuário:
\n\n{\n "name": "Alexey",\n "age": 30,\n "email": "alexey@example.com",\n "is_active": true\n}\n\nVamos criar a estrutura correspondente e adicionar os atributos para serialização:
\n\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize)]\nstruct User {\n name: String,\n age: u32,\n email: String,\n is_active: bool,\n}\n\nA macro #[derive(Debug)] permite exibir a estrutura no console para depuração. Sem ela, você não poderá usar println!("{:?}", user).
Parsing de uma string JSON
\n\nAgora vamos escrever uma função que recebe uma string JSON e retorna a estrutura User:
fn parse_user(json_str: &str) -> Result<User, serde_json::Error> {\n let user: User = serde_json::from_str(json_str)?;\n Ok(user)\n}\n\nfn main() {\n let data = r#"\n {\n "name": "Alexey",\n "age": 30,\n "email": "alexey@example.com",\n "is_active": true\n }\n "#;\n\n match parse_user(data) {\n Ok(user) => println!("Usuário: {:?}", user),\n Err(e) => eprintln!("Erro de parsing: {}", e),\n }\n}\n\nPonto chave: serde_json::from_str automaticamente mapeia os campos do JSON para os campos da estrutura. Se os nomes dos campos no JSON diferirem dos nomes em Rust (por exemplo, JSON usa snake_case e Rust usa camelCase), você pode usar o atributo #[serde(rename = "nome_do_campo")].
Tratamento de estruturas aninhadas
\n\nJSON frequentemente contém objetos aninhados. Vamos considerar um exemplo com endereço de usuário:
\n\n{\n "name": "Alexey",\n "address": {\n "city": "Moscou",\n "street": "Tverskaya",\n "zip": "101000"\n }\n}\n\nVamos criar estruturas aninhadas:
\n\n#[derive(Debug, Serialize, Deserialize