Serializar Struct para JSON em Rust
Serializar dados Rust para JSON é essencial para APIs, configurações e troca de dados. A crate serde com serde_json torna isso simples e seguro com a derive macro Serialize.
Dependências
Cargo.toml:
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Serialização básica com Serialize
Adicione #[derive(Serialize)] à sua struct:
use serde::Serialize;
#[derive(Serialize)]
struct Produto {
nome: String,
preco: f64,
em_estoque: bool,
tags: Vec<String>,
}
fn main() {
let produto = Produto {
nome: "Notebook Gamer".to_string(),
preco: 7499.90,
em_estoque: true,
tags: vec!["eletrônico".to_string(), "computador".to_string()],
};
// Serializar para String JSON compacta
let json = serde_json::to_string(&produto).unwrap();
println!("Compacto: {}", json);
// Pretty print (formatado)
let json_bonito = serde_json::to_string_pretty(&produto).unwrap();
println!("\nFormatado:\n{}", json_bonito);
}
Saída:
Compacto: {"nome":"Notebook Gamer","preco":7499.9,"em_estoque":true,"tags":["eletrônico","computador"]}
Formatado:
{
"nome": "Notebook Gamer",
"preco": 7499.9,
"em_estoque": true,
"tags": [
"eletrônico",
"computador"
]
}
Structs aninhadas
Serialize estruturas complexas com structs aninhadas:
use serde::Serialize;
#[derive(Serialize)]
struct Endereco {
rua: String,
cidade: String,
estado: String,
cep: String,
}
#[derive(Serialize)]
struct Contato {
tipo_contato: String,
valor: String,
}
#[derive(Serialize)]
struct Cliente {
id: u32,
nome: String,
endereco: Endereco,
contatos: Vec<Contato>,
}
fn main() {
let cliente = Cliente {
id: 1,
nome: "Ana Oliveira".to_string(),
endereco: Endereco {
rua: "Rua das Flores, 123".to_string(),
cidade: "São Paulo".to_string(),
estado: "SP".to_string(),
cep: "01234-567".to_string(),
},
contatos: vec![
Contato {
tipo_contato: "email".to_string(),
valor: "ana@exemplo.com".to_string(),
},
Contato {
tipo_contato: "telefone".to_string(),
valor: "+55 11 99999-0000".to_string(),
},
],
};
let json = serde_json::to_string_pretty(&cliente).unwrap();
println!("{}", json);
}
Saída:
{
"id": 1,
"nome": "Ana Oliveira",
"endereco": {
"rua": "Rua das Flores, 123",
"cidade": "São Paulo",
"estado": "SP",
"cep": "01234-567"
},
"contatos": [
{
"tipo_contato": "email",
"valor": "ana@exemplo.com"
},
{
"tipo_contato": "telefone",
"valor": "+55 11 99999-0000"
}
]
}
Personalização com atributos serde
Controle como os campos são serializados:
use serde::Serialize;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct ConfigApi {
nome_servidor: String,
porta_http: u16,
modo_debug: bool,
#[serde(rename = "maxConexoes")]
max_conexoes: u32,
#[serde(skip_serializing_if = "Option::is_none")]
chave_secreta: Option<String>,
#[serde(skip)]
senha_interna: String,
#[serde(serialize_with = "serializar_como_string")]
versao: u32,
}
fn serializar_como_string<S>(valor: &u32, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&format!("v{}.0", valor))
}
fn main() {
let config = ConfigApi {
nome_servidor: "api-producao".to_string(),
porta_http: 8080,
modo_debug: false,
max_conexoes: 100,
chave_secreta: None, // será omitido no JSON
senha_interna: "s3cr3t".to_string(), // será ignorado
versao: 2,
};
let json = serde_json::to_string_pretty(&config).unwrap();
println!("{}", json);
// Com chave_secreta definida
let config_com_chave = ConfigApi {
nome_servidor: "api-dev".to_string(),
porta_http: 3000,
modo_debug: true,
max_conexoes: 10,
chave_secreta: Some("abc123".to_string()),
senha_interna: "s3cr3t".to_string(),
versao: 3,
};
let json2 = serde_json::to_string_pretty(&config_com_chave).unwrap();
println!("\n{}", json2);
}
Saída:
{
"nomeServidor": "api-producao",
"portaHttp": 8080,
"modoDebug": false,
"maxConexoes": 100,
"versao": "v2.0"
}
{
"nomeServidor": "api-dev",
"portaHttp": 3000,
"modoDebug": true,
"maxConexoes": 10,
"chaveSecreta": "abc123",
"versao": "v3.0"
}
Serializar para arquivo
Escreva JSON diretamente em um arquivo:
use serde::Serialize;
use std::fs::File;
use std::io::BufWriter;
#[derive(Serialize)]
struct Dados {
titulo: String,
registros: Vec<Registro>,
}
#[derive(Serialize)]
struct Registro {
id: u32,
valor: f64,
}
fn main() {
let dados = Dados {
titulo: "Relatório Mensal".to_string(),
registros: (1..=5).map(|i| Registro {
id: i,
valor: i as f64 * 123.45,
}).collect(),
};
// Serializar direto para arquivo (eficiente — sem String intermediária)
let arquivo = File::create("relatorio.json").unwrap();
let escritor = BufWriter::new(arquivo);
serde_json::to_writer_pretty(escritor, &dados).unwrap();
println!("JSON salvo em relatorio.json");
// Verificar o resultado
let conteudo = std::fs::read_to_string("relatorio.json").unwrap();
println!("{}", conteudo);
}
Saída:
JSON salvo em relatorio.json
{
"titulo": "Relatório Mensal",
"registros": [
{"id": 1, "valor": 123.45},
{"id": 2, "valor": 246.9},
{"id": 3, "valor": 370.35},
{"id": 4, "valor": 493.8},
{"id": 5, "valor": 617.25}
]
}
Serializar enums
Enums podem ser serializadas de diferentes formas:
use serde::Serialize;
#[derive(Serialize)]
#[serde(tag = "tipo")]
enum Forma {
#[serde(rename = "circulo")]
Circulo { raio: f64 },
#[serde(rename = "retangulo")]
Retangulo { largura: f64, altura: f64 },
#[serde(rename = "triangulo")]
Triangulo { base: f64, altura: f64 },
}
#[derive(Serialize)]
struct Desenho {
nome: String,
formas: Vec<Forma>,
}
fn main() {
let desenho = Desenho {
nome: "Meu Desenho".to_string(),
formas: vec![
Forma::Circulo { raio: 5.0 },
Forma::Retangulo { largura: 10.0, altura: 20.0 },
Forma::Triangulo { base: 8.0, altura: 6.0 },
],
};
let json = serde_json::to_string_pretty(&desenho).unwrap();
println!("{}", json);
}
Saída:
{
"nome": "Meu Desenho",
"formas": [
{
"tipo": "circulo",
"raio": 5.0
},
{
"tipo": "retangulo",
"largura": 10.0,
"altura": 20.0
},
{
"tipo": "triangulo",
"base": 8.0,
"altura": 6.0
}
]
}
Referência rápida
| Função | Descrição |
|---|---|
to_string() | Serializa para String compacta |
to_string_pretty() | Serializa com indentação |
to_writer() | Serializa direto para Write (arquivo, buffer) |
to_writer_pretty() | Serializa formatado para Write |
to_vec() | Serializa para Vec<u8> |
Veja também
- Parse JSON em Rust — a operação inversa (JSON para Rust)
- Fazer Requisição HTTP — envie JSON em requisições HTTP
- Criar Servidor HTTP — retorne JSON no seu servidor
- Escrever em Arquivo — salve JSON em arquivos
- Ler Arquivo CSV — outra forma de serialização de dados
- Documentação da crate: serde_json