Como Concatenar Strings em Zig
Em Zig, strings são slices de bytes ([]const u8), e a linguagem não possui um operador + para concatenação como em outras linguagens. Em vez disso, Zig oferece abordagens explícitas e eficientes que lhe dão controle total sobre a alocação de memória.
Nesta receita, vamos explorar várias técnicas para concatenar strings em Zig.
Concatenação em Tempo de Compilação (comptime)
A forma mais simples de concatenar strings é em tempo de compilação, usando o operador ++. Isso funciona apenas quando ambos os operandos são conhecidos em comptime.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Concatenação em comptime com ++
const saudacao = "Olá, " ++ "Mundo!";
try stdout.print("{s}\n", .{saudacao});
// Concatenar múltiplas partes
const frase = "Zig " ++ "é " ++ "uma " ++ "linguagem " ++ "incrível!";
try stdout.print("{s}\n", .{frase});
// Concatenar com caracteres especiais
const com_newline = "Primeira linha\n" ++ "Segunda linha\n";
try stdout.print("{s}", .{com_newline});
// Repetição de strings em comptime
const separador = "-" ** 20;
try stdout.print("{s}\n", .{separador});
}
Saída esperada:
Olá, Mundo!
Zig é uma linguagem incrível!
Primeira linha
Segunda linha
--------------------
Concatenação com std.mem.concat
A função std.mem.concat aloca memória e concatena múltiplos slices em um único slice.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Concatenar duas strings
const nome = "Maria";
const sobrenome = "Silva";
const nome_completo = try std.mem.concat(allocator, u8, &.{ nome, " ", sobrenome });
defer allocator.free(nome_completo);
try stdout.print("Nome: {s}\n", .{nome_completo});
// Concatenar múltiplas partes
const caminho = try std.mem.concat(allocator, u8, &.{ "/home", "/", "usuario", "/", "documentos" });
defer allocator.free(caminho);
try stdout.print("Caminho: {s}\n", .{caminho});
}
Saída esperada:
Nome: Maria Silva
Caminho: /home/usuario/documentos
Concatenação com std.fmt.allocPrint
Usar std.fmt.allocPrint é uma abordagem muito flexível que permite incluir formatação durante a concatenação.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Concatenar com formatação
const nome = "João";
const idade: u32 = 28;
const apresentacao = try std.fmt.allocPrint(allocator, "Meu nome é {s} e tenho {d} anos.", .{ nome, idade });
defer allocator.free(apresentacao);
try stdout.print("{s}\n", .{apresentacao});
// Construir URL com parâmetros
const base = "https://api.exemplo.com";
const endpoint = "usuarios";
const id: u64 = 42;
const url = try std.fmt.allocPrint(allocator, "{s}/{s}/{d}", .{ base, endpoint, id });
defer allocator.free(url);
try stdout.print("URL: {s}\n", .{url});
// Concatenar string com número formatado
const preco: f64 = 49.99;
const texto = try std.fmt.allocPrint(allocator, "Preço: R$ {d:.2}", .{preco});
defer allocator.free(texto);
try stdout.print("{s}\n", .{texto});
}
Saída esperada:
Meu nome é João e tenho 28 anos.
URL: https://api.exemplo.com/usuarios/42
Preço: R$ 49.99
Concatenação com Buffer Fixo (Sem Alocação)
Quando você quer evitar alocações dinâmicas, pode usar std.fmt.bufPrint com um buffer de tamanho fixo.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var buffer: [256]u8 = undefined;
// Concatenar em buffer fixo
const parte1 = "Olá";
const parte2 = "Mundo";
const resultado = try std.fmt.bufPrint(&buffer, "{s}, {s}!", .{ parte1, parte2 });
try stdout.print("Resultado: {s}\n", .{resultado});
// Múltiplas partes com formatação
const dia: u32 = 21;
const mes = "fevereiro";
const ano: u32 = 2026;
const data = try std.fmt.bufPrint(&buffer, "{d} de {s} de {d}", .{ dia, mes, ano });
try stdout.print("Data: {s}\n", .{data});
}
Saída esperada:
Resultado: Olá, Mundo!
Data: 21 de fevereiro de 2026
Concatenação com ArrayList (Construção Incremental)
Para construir strings de forma incremental (como um StringBuilder em Java), use std.ArrayList(u8).
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Usar ArrayList como StringBuilder
var builder = std.ArrayList(u8).init(allocator);
defer builder.deinit();
// Adicionar texto incrementalmente
try builder.appendSlice("SELECT * FROM usuarios");
try builder.appendSlice(" WHERE ativo = true");
try builder.appendSlice(" ORDER BY nome");
try builder.appendSlice(" LIMIT 10;");
const query = builder.items;
try stdout.print("Query: {s}\n", .{query});
// Construir com writer do ArrayList
var builder2 = std.ArrayList(u8).init(allocator);
defer builder2.deinit();
const writer = builder2.writer();
try writer.print("Item {d}: {s} - R$ {d:.2}", .{ 1, "Teclado", 199.90 });
try stdout.print("Produto: {s}\n", .{builder2.items});
}
Saída esperada:
Query: SELECT * FROM usuarios WHERE ativo = true ORDER BY nome LIMIT 10;
Produto: Item 1: Teclado - R$ 199.90
Juntar (Join) Array de Strings
Para juntar múltiplas strings com um separador, use std.mem.join.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Juntar palavras com espaço
const palavras = [_][]const u8{ "Zig", "é", "fantástico" };
const frase = try std.mem.join(allocator, " ", &palavras);
defer allocator.free(frase);
try stdout.print("Frase: {s}\n", .{frase});
// Juntar com vírgula
const frutas = [_][]const u8{ "maçã", "banana", "laranja", "uva" };
const lista = try std.mem.join(allocator, ", ", &frutas);
defer allocator.free(lista);
try stdout.print("Frutas: {s}\n", .{lista});
// Juntar caminhos com separador
const partes = [_][]const u8{ "home", "usuario", "projetos", "meu-app" };
const caminho = try std.mem.join(allocator, "/", &partes);
defer allocator.free(caminho);
try stdout.print("Caminho: /{s}\n", .{caminho});
}
Saída esperada:
Frase: Zig é fantástico
Frutas: maçã, banana, laranja, uva
Caminho: /home/usuario/projetos/meu-app
Tabela Comparativa de Métodos
| Método | Alocação | Uso Ideal |
|---|---|---|
++ (comptime) | Nenhuma | Strings conhecidas em compilação |
std.mem.concat | Heap | Concatenar slices existentes |
std.fmt.allocPrint | Heap | Formatação + concatenação |
std.fmt.bufPrint | Stack | Evitar alocação heap |
ArrayList(u8) | Heap | Construção incremental |
std.mem.join | Heap | Juntar com separador |
Veja Também
- Formatar Strings com std.fmt — Aprenda mais sobre formatação
- Dividir (Split) Strings — Operação inversa: dividir strings
- Usando ArenaAllocator — Simplifique a liberação de memória
- Arrays Dinâmicos com ArrayList — Mais sobre ArrayList