Introdução
Gerar JSON é tão importante quanto parseá-lo. Seja para responder a uma API, salvar configurações ou exportar dados, a serialização JSON é uma operação fundamental. Em Zig, std.json.stringify e std.json.stringifyAlloc permitem converter structs e valores Zig diretamente para JSON.
Nesta receita, você aprenderá a serializar diferentes tipos de dados para JSON.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento de parsing JSON em Zig
Serializar uma Struct Simples
Converta uma struct Zig diretamente para JSON:
const std = @import("std");
const Usuario = struct {
nome: []const u8,
email: []const u8,
idade: u32,
ativo: bool,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const usuario = Usuario{
.nome = "Maria Silva",
.email = "maria@exemplo.com",
.idade = 28,
.ativo = true,
};
// Serializar para string alocada
const json = try std.json.stringifyAlloc(allocator, usuario, .{});
defer allocator.free(json);
std.debug.print("{s}\n", .{json});
}
Saída esperada
{"nome":"Maria Silva","email":"maria@exemplo.com","idade":28,"ativo":true}
JSON Formatado (Pretty Print)
Para JSON legível com indentação:
const std = @import("std");
const Configuracao = struct {
servidor: struct {
host: []const u8,
porta: u16,
},
banco_dados: struct {
url: []const u8,
pool_size: u32,
},
debug: bool,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const config = Configuracao{
.servidor = .{
.host = "0.0.0.0",
.porta = 8080,
},
.banco_dados = .{
.url = "postgresql://localhost:5432/meubanco",
.pool_size = 10,
},
.debug = false,
};
// Serializar com formatação (indentação de 4 espaços)
const json = try std.json.stringifyAlloc(allocator, config, .{
.whitespace = .indent_4,
});
defer allocator.free(json);
std.debug.print("{s}\n", .{json});
}
Saída esperada
{
"servidor": {
"host": "0.0.0.0",
"porta": 8080
},
"banco_dados": {
"url": "postgresql://localhost:5432/meubanco",
"pool_size": 10
},
"debug": false
}
Serializar para um Writer
Escreva JSON diretamente para qualquer writer (arquivo, buffer, rede):
const std = @import("std");
const Evento = struct {
tipo: []const u8,
timestamp: i64,
dados: []const u8,
};
pub fn main() !void {
const evento = Evento{
.tipo = "login",
.timestamp = 1740100000,
.dados = "usuario=maria",
};
// Escrever para stdout
const stdout = std.io.getStdOut().writer();
try std.json.stringify(evento, .{}, stdout);
try stdout.writeByte('\n');
// Escrever para buffer fixo
var buffer: [256]u8 = undefined;
var stream = std.io.fixedBufferStream(&buffer);
try std.json.stringify(evento, .{}, stream.writer());
const json = stream.getWritten();
std.debug.print("Buffer: {s}\n", .{json});
}
Serializar Arrays e Slices
Arrays e slices são automaticamente convertidos para arrays JSON:
const std = @import("std");
const Produto = struct {
id: u64,
nome: []const u8,
preco: f64,
tags: []const []const u8,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const produtos = [_]Produto{
.{
.id = 1,
.nome = "Notebook",
.preco = 4599.90,
.tags = &.{ "eletrônico", "computador" },
},
.{
.id = 2,
.nome = "Teclado",
.preco = 299.90,
.tags = &.{ "periférico", "acessório" },
},
.{
.id = 3,
.nome = "Monitor",
.preco = 1899.90,
.tags = &.{ "eletrônico", "display" },
},
};
const json = try std.json.stringifyAlloc(allocator, &produtos, .{
.whitespace = .indent_2,
});
defer allocator.free(json);
std.debug.print("{s}\n", .{json});
}
Campos Opcionais (null em JSON)
Campos opcionais ?T são serializados como null quando não tem valor:
const std = @import("std");
const Perfil = struct {
nome: []const u8,
bio: ?[]const u8,
site: ?[]const u8,
seguidores: ?u32,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Perfil completo
const perfil_completo = Perfil{
.nome = "João Dev",
.bio = "Desenvolvedor Zig apaixonado",
.site = "https://joaodev.com",
.seguidores = 1500,
};
const json1 = try std.json.stringifyAlloc(allocator, perfil_completo, .{
.whitespace = .indent_2,
});
defer allocator.free(json1);
std.debug.print("Completo:\n{s}\n\n", .{json1});
// Perfil mínimo (campos opcionais como null)
const perfil_minimo = Perfil{
.nome = "Ana",
.bio = null,
.site = null,
.seguidores = null,
};
const json2 = try std.json.stringifyAlloc(allocator, perfil_minimo, .{
.whitespace = .indent_2,
});
defer allocator.free(json2);
std.debug.print("Mínimo:\n{s}\n", .{json2});
}
Saída esperada
Completo:
{
"nome": "João Dev",
"bio": "Desenvolvedor Zig apaixonado",
"site": "https://joaodev.com",
"seguidores": 1500
}
Mínimo:
{
"nome": "Ana",
"bio": null,
"site": null,
"seguidores": null
}
Construir JSON Dinamicamente
Para JSON com estrutura dinâmica, use std.json.Value:
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Criar objeto JSON dinamicamente
var root = std.json.Value{ .object = std.json.ObjectMap.init(allocator) };
defer root.object.deinit();
try root.object.put("versao", .{ .string = "1.0.0" });
try root.object.put("nome", .{ .string = "meu-app" });
try root.object.put("porta", .{ .integer = 3000 });
// Criar sub-objeto
var deps = std.json.ObjectMap.init(allocator);
defer deps.deinit();
try deps.put("std", .{ .string = "0.13.0" });
try root.object.put("dependencias", .{ .object = deps });
// Serializar
const json = try std.json.stringifyAlloc(allocator, root, .{
.whitespace = .indent_2,
});
defer allocator.free(json);
std.debug.print("{s}\n", .{json});
}
Dicas e Boas Práticas
Use structs para JSON estático: Quando a estrutura é conhecida, structs são mais eficientes e seguras.
Escolha a formatação: Use
.whitespace = .indent_2ou.indent_4para arquivos de configuração legíveis. Sem whitespace para dados de rede.Writers para streaming: Use
std.json.stringifycom um writer para evitar alocações grandes.Campos opcionais: Use
?Tpara campos que podem sernullno JSON.Combine com HTTP: Use a serialização para enviar dados via HTTP POST.
Receitas Relacionadas
- Como parsear JSON em Zig - Operação inversa
- Como ler/escrever JSON em arquivos - Persistência
- Como validar JSON em Zig - Validação
- Como fazer requisições HTTP POST em Zig - Enviar JSON via HTTP