Vamos dar continuidade a nossa Série sobre Zig!
Na postagem anterior vimos:
E nessa postagem veremos:
Zig possui tipos de dados simples e explícitos, com forte foco em controle e desempenho. Abaixo, os principais:
i8
, i16
, i32
, i64
, i128
u8
, u16
, u32
, u64
, u128
usize
(tamanho de ponteiro), isize
const a: i32 = -10;
const b: u64 = 42;
const size: usize = 1024;
f16
, f32
, f64
, f128
(dependendo da plataforma)const pi: f64 = 3.1415;
const small: f32 = 0.0001;
bool
(true
ou false
)const is_valid: bool = true;
*T
: ponteiro simples[*]T
: fatia de comprimento fixo[]T
: fatia de comprimento dinâmico?*T
: ponteiro opcional (pode ser null
)const x: i32 = 10;
const px: *const i32 = &x; // ponteiro constante
const buffer: []u8 = "abc"; // slice dinâmica
[N]T
: array de tamanho fixo[]const u8
: string (sem null terminator)const fixed: [3]u8 = .{1, 2, 3};
const str: []const u8 = "Zig!";
enum { A, B, C }
: mapeia para inteirosconst State = enum { Idle, Running, Done };
var s: State = State.Idle;
struct { x: i32, y: i32 }
: agrupamento de campos com tipos definidosconst Vec2 = struct {
x: f32,
y: f32,
};
const v = Vec2{ .x = 1.0, .y = 2.0 };
union(enum) { A: i32, B: f32 }
: tipo com variantes exclusivasconst Value = union(enum) {
Int: i32,
Float: f32,
};
var v = Value{ .Int = 10 };
?T
: tipo que pode ser null
const maybe_value: ?i32 = null;
if (maybe_value) |val| {
std.debug.print("Valor: {}\n", .{val});
}
error{Err1, Err2}
: enum de erros!T
: retorno que pode ser valor ou erroconst MyError = error{ NotFound };
fn get() !i32 {
return MyError.NotFound;
}
comptime T
: tipo avaliado em tempo de compilaçãofn printType(comptime T: type) void {
std.debug.print("Tipo: {}\n", .{@typeName(T)});
}
fn identity(value: anytype) @TypeOf(value) {
return value;
}
void
: ausência de valornoreturn
: função que nunca retorna (ex: loop infinito ou panic)fn doNothing() void {}
fn crash() noreturn {
while (true) {}
}
Usando os tipos em contexto funcional:
switch
const std = @import("std");
const State = enum {
Idle,
Running,
Finished,
};
fn handleState(state: State) void {
switch (state) {
State.Idle => std.debug.print("Idle\n", .{}),
State.Running => std.debug.print("Running\n", .{}),
State.Finished => std.debug.print("Finished\n", .{}),
}
}
pub fn main() void {
handleState(State.Running);
}
const std = @import("std");
fn maybeFind(value: i32) ?i32 {
if (value > 0) return value;
return null;
}
pub fn main() void {
const result = maybeFind(5);
if (result) |val| {
std.debug.print("Found: {}\n", .{val});
} else {
std.debug.print("Not found\n", .{});
}
}
Uso de arrays.
Nesse caso estamos usando std::vector, mas podia ser quaisquer outros, exemplos:
deque, list,
unordered_list
, set,unordered_set
, array,forward_list
, multiset,unordered_multiset
, queue,priority_queue
, map ou unordered_map.
#include <iostream>
#include <vector>
int main(){
std::vector<std::string> langs {"C++", "C", "Go", "Zig", "Java"};
std::cout << "Imprimindo todos os elementos:\n";
for(const auto& target : langs){
std::cout << target << ' ';
}
std::cout.put('\n');
std::cout << "Adicionando 1 elemento ao final:\n";
langs.push_back("Python");
std::cout << "Adicionando 1 elemento a 3º posição:\n";
langs.insert(langs.begin() + 2, "Assembly");
std::cout << "Removendo o 1º elemento:\n";
langs.erase(langs.begin());
std::cout << "Removendo o último elemento:\n";
langs.pop_back();
std::cout << "Removendo o 3º elemento:\n";
if (langs.size() > 2) langs.erase(langs.begin() + 2);
std::cout << "Remover elemento por nome(Assembly):\n";
langs.erase(std::remove(langs.begin(), langs.end(), "Assembly"), langs.end());
std::cout << "Adicionando 1 elemento no início:\n";
langs.insert(langs.begin(), "C++"); // Ou langs.emplace(langs.begin(), "C++");
std::cout << "Imprimindo todos os elementos:\n";
for(const auto& target : langs){
std::cout << target << ' ';
}
std::cout.put('\n');
}
std.ArrayList([]const u8)
com alocador padrão(heap):const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
var langs = std.ArrayList([]const u8).init(allocator);
// Inicializar a lista
try langs.appendSlice(&[_][]const u8{
"C++", "C", "Go", "Zig", "Java"
});
std.debug.print("Imprimindo todos os elementos:\n", .{});
printList(langs.items);
// Adiciona no final
std.debug.print("Adicionando 1 elemento ao final:\n", .{});
try langs.append("Python");
// Insere na posição 2 (índice 2 == 3º elemento)
std.debug.print("Adicionando 1 elemento a 3º posição:\n", .{});
try langs.insert(2, "Assembly");
// Remove o primeiro
std.debug.print("Removendo o 1º elemento:\n", .{});
_ = langs.orderedRemove(0);
// Remove o último
std.debug.print("Removendo o último elemento:\n", .{});
_ = langs.pop();
// Remove o 3º (índice 2)
std.debug.print("Removendo o 3º elemento:\n", .{});
if (langs.items.len > 2) {
_ = langs.orderedRemove(2);
}
// Remove "Assembly" por nome
std.debug.print("Remover elemento por nome(Assembly):\n", .{});
var i: usize = 0;
while (i < langs.items.len) {
if (std.mem.eql(u8, langs.items[i], "Assembly")) {
_ = langs.orderedRemove(i);
} else {
i += 1;
}
}
// Adiciona no início
std.debug.print("Adicionando 1 elemento no início:\n", .{});
try langs.insert(0, "C++");
// Imprime lista final
std.debug.print("Imprimindo todos os elementos:\n", .{});
printList(langs.items);
// Libera memória
langs.deinit();
}
fn printList(list: []const []const u8) void {
for (list) |item| {
std.debug.print("{s} ", .{item});
}
std.debug.print("\n", .{});
}
std.ArrayList
permite comportamento similar ao std::vector
.orderedRemove(index)
remove e preserva a ordem (como erase
em C++).[]const u8
(fatias).allocator
usado é o page_allocator
por simplicidade.Você também poderia usar: std.heap.ArenaAllocator
ou lista com []std.BoundedArray
.