Parse JSON em Rust
A crate serde_json é a ferramenta padrão para trabalhar com JSON em Rust. Ela permite deserializar JSON tanto para structs tipadas quanto para valores dinâmicos, com excelente performance e segurança de tipos.
Dependências
Cargo.toml:
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Parse básico com Value (dinâmico)
Para JSON de estrutura desconhecida ou variável, use serde_json::Value:
use serde_json::Value;
fn main() {
let json_str = r#"
{
"nome": "Maria Silva",
"idade": 30,
"ativa": true,
"endereco": {
"cidade": "São Paulo",
"estado": "SP"
},
"hobbies": ["leitura", "programação", "corrida"]
}
"#;
// Parse para Value
let valor: Value = serde_json::from_str(json_str).unwrap();
// Acessar campos com indexação
println!("Nome: {}", valor["nome"]);
println!("Idade: {}", valor["idade"]);
println!("Cidade: {}", valor["endereco"]["cidade"]);
println!("Primeiro hobby: {}", valor["hobbies"][0]);
// Acessar como tipos Rust
if let Some(nome) = valor["nome"].as_str() {
println!("Nome (str): {}", nome);
}
if let Some(idade) = valor["idade"].as_i64() {
println!("Idade (i64): {}", idade);
}
if let Some(ativa) = valor["ativa"].as_bool() {
println!("Ativa (bool): {}", ativa);
}
// Iterar sobre array
if let Some(hobbies) = valor["hobbies"].as_array() {
print!("Hobbies:");
for hobby in hobbies {
print!(" {}", hobby.as_str().unwrap_or("?"));
}
println!();
}
// Campo inexistente retorna Null (sem pânico)
println!("Campo inexistente: {}", valor["nao_existe"]);
}
Saída:
Nome: "Maria Silva"
Idade: 30
Cidade: "São Paulo"
Primeiro hobby: "leitura"
Nome (str): Maria Silva
Idade (i64): 30
Ativa (bool): true
Hobbies: leitura programação corrida
Campo inexistente: null
Deserialização tipada com structs
A forma mais segura e idiomática — mapeie JSON para structs Rust:
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Usuario {
nome: String,
idade: u32,
email: String,
#[serde(default)]
ativo: bool,
#[serde(rename = "dataCadastro")]
data_cadastro: Option<String>,
}
fn main() {
let json_str = r#"
{
"nome": "João Santos",
"idade": 25,
"email": "joao@exemplo.com",
"ativo": true,
"dataCadastro": "2026-01-15"
}
"#;
// Deserializar para struct
let usuario: Usuario = serde_json::from_str(json_str).unwrap();
println!("Usuário: {:?}", usuario);
println!("Nome: {}", usuario.nome);
println!("Idade: {}", usuario.idade);
println!("Cadastro: {}", usuario.data_cadastro.unwrap_or_default());
// JSON sem campo opcional
let json_parcial = r#"
{
"nome": "Ana Lima",
"idade": 22,
"email": "ana@exemplo.com"
}
"#;
let usuario2: Usuario = serde_json::from_str(json_parcial).unwrap();
println!("\nUsuário 2: {:?}", usuario2);
println!("Ativo (padrão): {}", usuario2.ativo);
println!("Data: {:?}", usuario2.data_cadastro);
}
Saída:
Usuário: Usuario { nome: "João Santos", idade: 25, email: "joao@exemplo.com", ativo: true, data_cadastro: Some("2026-01-15") }
Nome: João Santos
Idade: 25
Cadastro: 2026-01-15
Usuário 2: Usuario { nome: "Ana Lima", idade: 22, email: "ana@exemplo.com", ativo: false, data_cadastro: None }
Ativo (padrão): false
Data: None
Parse de array JSON
Deserialize arrays JSON para Vec<T>:
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Tarefa {
id: u32,
titulo: String,
concluida: bool,
}
fn main() {
let json_array = r#"
[
{"id": 1, "titulo": "Aprender Rust", "concluida": true},
{"id": 2, "titulo": "Criar API REST", "concluida": false},
{"id": 3, "titulo": "Escrever testes", "concluida": false},
{"id": 4, "titulo": "Deploy em produção", "concluida": false}
]
"#;
let tarefas: Vec<Tarefa> = serde_json::from_str(json_array).unwrap();
println!("Total de tarefas: {}", tarefas.len());
println!();
for tarefa in &tarefas {
let status = if tarefa.concluida { "[x]" } else { "[ ]" };
println!("{} #{}: {}", status, tarefa.id, tarefa.titulo);
}
// Filtrar tarefas pendentes
let pendentes: Vec<&Tarefa> = tarefas.iter()
.filter(|t| !t.concluida)
.collect();
println!("\nPendentes: {}", pendentes.len());
}
Saída:
Total de tarefas: 4
[x] #1: Aprender Rust
[ ] #2: Criar API REST
[ ] #3: Escrever testes
[ ] #4: Deploy em produção
Pendentes: 3
Tratamento de erros no parse
Trate erros de deserialização de forma robusta:
use serde::Deserialize;
use serde_json;
#[derive(Debug, Deserialize)]
struct Config {
host: String,
porta: u16,
debug: bool,
}
fn parse_config(json: &str) -> Result<Config, String> {
serde_json::from_str(json)
.map_err(|e| format!("Erro no JSON: {} (linha {}, coluna {})",
e, e.line(), e.column()))
}
fn main() {
// JSON válido
let valido = r#"{"host": "localhost", "porta": 8080, "debug": true}"#;
match parse_config(valido) {
Ok(config) => println!("Config: {:?}", config),
Err(e) => println!("Erro: {}", e),
}
// JSON com tipo errado
let tipo_errado = r#"{"host": "localhost", "porta": "não_é_número", "debug": true}"#;
match parse_config(tipo_errado) {
Ok(config) => println!("Config: {:?}", config),
Err(e) => println!("Erro: {}", e),
}
// JSON mal formado
let mal_formado = r#"{"host": "localhost", porta: 8080}"#;
match parse_config(mal_formado) {
Ok(config) => println!("Config: {:?}", config),
Err(e) => println!("Erro: {}", e),
}
// JSON com campo faltando
let incompleto = r#"{"host": "localhost"}"#;
match parse_config(incompleto) {
Ok(config) => println!("Config: {:?}", config),
Err(e) => println!("Erro: {}", e),
}
}
Saída:
Config: Config { host: "localhost", porta: 8080, debug: true }
Erro: Erro no JSON: invalid type: string "não_é_número", expected u16 (linha 1, coluna 47)
Erro: Erro no JSON: key must be a string at line 1 column 25 (linha 1, coluna 25)
Erro: Erro no JSON: missing field `porta` at line 1 column 22 (linha 1, coluna 22)
Parse de JSON de arquivo
Leia e parse um arquivo JSON diretamente:
use serde::Deserialize;
use std::fs::File;
use std::io::BufReader;
#[derive(Debug, Deserialize)]
struct Dados {
titulo: String,
itens: Vec<String>,
}
fn main() {
// Criar arquivo JSON de exemplo
std::fs::write("dados.json", r#"
{
"titulo": "Minha Lista",
"itens": ["Item 1", "Item 2", "Item 3"]
}
"#).unwrap();
// Ler e parsear diretamente do arquivo
let arquivo = File::open("dados.json").expect("Erro ao abrir arquivo");
let leitor = BufReader::new(arquivo);
let dados: Dados = serde_json::from_reader(leitor)
.expect("Erro ao parsear JSON do arquivo");
println!("Título: {}", dados.titulo);
for item in &dados.itens {
println!(" - {}", item);
}
}
Saída:
Título: Minha Lista
- Item 1
- Item 2
- Item 3
Construir JSON com json! macro
Crie valores JSON inline sem definir structs:
use serde_json::json;
fn main() {
let nome = "Rust";
let versao = 2026;
let valor = json!({
"linguagem": nome,
"ano": versao,
"caracteristicas": ["segura", "rápida", "concorrente"],
"detalhes": {
"tipagem": "estática",
"paradigma": "multi-paradigma"
}
});
// Pretty print
let formatado = serde_json::to_string_pretty(&valor).unwrap();
println!("{}", formatado);
}
Saída:
{
"ano": 2026,
"caracteristicas": [
"segura",
"rápida",
"concorrente"
],
"detalhes": {
"paradigma": "multi-paradigma",
"tipagem": "estática"
},
"linguagem": "Rust"
}
Veja também
- Serializar Struct para JSON — a operação inversa (Rust para JSON)
- Fazer Requisição HTTP — parse de respostas JSON de APIs
- Criar Servidor HTTP — receba JSON no seu servidor
- Ler Arquivo em Rust — leitura de arquivos para parse
- Converter String para Número — conversões de tipos básicos
- Documentação da crate: serde_json