@field em Zig
O @field permite acessar campos de structs, unions e enums usando um nome de campo determinado em tempo de compilação (comptime). Isso é fundamental para metaprogramação, pois permite iterar sobre campos e acessá-los dinamicamente sem escrever código para cada campo individualmente.
Sintaxe
@field(objeto: anytype, comptime nome_campo: []const u8) FieldType
O que faz
O @field acessa o valor de um campo específico de uma struct, union ou enum usando uma string com o nome do campo. Embora o nome seja uma string, ele deve ser conhecido em tempo de compilação (comptime), o que permite ao compilador verificar a existência do campo e resolver seu tipo estaticamente.
Parâmetros
- objeto (
anytype): A instância da struct, union ou enum cujo campo será acessado. Pode ser um valor ou um ponteiro. - nome_campo (
[]const u8, comptime): O nome do campo como string literal ou valor comptime. Deve corresponder a um campo existente no tipo.
Valor de retorno
Retorna o valor do campo especificado. O tipo retornado é o tipo declarado para aquele campo na definição da struct/union.
Exemplos práticos
Exemplo 1: Acesso dinâmico a campos
const std = @import("std");
const Pessoa = struct {
nome: []const u8,
idade: u32,
email: []const u8,
};
test "acesso dinâmico a campos" {
const pessoa = Pessoa{
.nome = "Maria",
.idade = 30,
.email = "maria@exemplo.com",
};
// Acessar campos por nome
try std.testing.expectEqualStrings("Maria", @field(pessoa, "nome"));
try std.testing.expect(@field(pessoa, "idade") == 30);
try std.testing.expectEqualStrings("maria@exemplo.com", @field(pessoa, "email"));
}
Exemplo 2: Serialização genérica iterando sobre campos
const std = @import("std");
fn toQueryString(comptime T: type, valor: T) ![]u8 {
var buffer: [1024]u8 = undefined;
var stream = std.io.fixedBufferStream(&buffer);
const writer = stream.writer();
const fields = @typeInfo(T).@"struct".fields;
inline for (fields, 0..) |campo, i| {
if (i > 0) try writer.writeByte('&');
const campo_valor = @field(valor, campo.name);
try writer.print("{s}=", .{campo.name});
if (@TypeOf(campo_valor) == []const u8) {
try writer.writeAll(campo_valor);
} else {
try writer.print("{}", .{campo_valor});
}
}
return stream.getWritten();
}
const Filtro = struct {
pagina: u32,
limite: u32,
ordem: []const u8,
};
test "query string genérica" {
const filtro = Filtro{
.pagina = 1,
.limite = 20,
.ordem = "nome",
};
const qs = try toQueryString(Filtro, filtro);
// Resultado: "pagina=1&limite=20&ordem=nome"
try std.testing.expectEqualStrings("pagina=1&limite=20&ordem=nome", qs);
}
Exemplo 3: Comparação genérica de structs
const std = @import("std");
fn structsIguais(comptime T: type, a: T, b: T) bool {
const fields = @typeInfo(T).@"struct".fields;
inline for (fields) |campo| {
const val_a = @field(a, campo.name);
const val_b = @field(b, campo.name);
if (campo.type == []const u8) {
if (!std.mem.eql(u8, val_a, val_b)) return false;
} else {
if (val_a != val_b) return false;
}
}
return true;
}
const Coordenada = struct {
x: i32,
y: i32,
z: i32,
};
test "comparação genérica" {
const a = Coordenada{ .x = 1, .y = 2, .z = 3 };
const b = Coordenada{ .x = 1, .y = 2, .z = 3 };
const c = Coordenada{ .x = 1, .y = 2, .z = 4 };
try std.testing.expect(structsIguais(Coordenada, a, b));
try std.testing.expect(!structsIguais(Coordenada, a, c));
}
Casos de uso comuns
- Serialização/Deserialização: Iterar sobre campos de structs para converter automaticamente para JSON, CSV, query strings, etc.
- ORM e mapeamento de dados: Mapear colunas de banco de dados para campos de struct dinamicamente.
- Validação genérica: Verificar valores de todos os campos de uma struct de forma genérica.
- Comparação e hash: Implementar igualdade e hash para structs arbitrárias.
- Clonagem de structs: Copiar seletivamente campos entre structs de tipos diferentes.
Builtins relacionados
- @hasField — Verifica se um tipo possui determinado campo antes de acessá-lo
- @typeInfo — Lista todos os campos de um tipo
- @hasDecl — Verifica existência de declarações (funções, constantes)
- @typeName — Obtém nome do tipo para mensagens de erro