Zig Série: Parte III

⚡ Tipos de dados e Arrays.


Zig Série: Parte III


Vamos dar continuidade a nossa Série sobre Zig!

Na postagem anterior vimos:

  • Comentários
  • Variáveis
  • Concatenação
  • e Constantes

E nessa postagem veremos:

  • Tipos de dados
  • e Arrays


Tipos de Dados em Zig

Zig possui tipos de dados simples e explícitos, com forte foco em controle e desempenho. Abaixo, os principais:

1. Tipos Inteiros

  • Com sinal: i8, i16, i32, i64, i128
  • Sem sinal: u8, u16, u32, u64, u128
  • Inteiro genérico: usize (tamanho de ponteiro), isize
const a: i32 = -10;
const b: u64 = 42;
const size: usize = 1024;

2. Ponto Flutuante

  • f16, f32, f64, f128 (dependendo da plataforma)
const pi: f64 = 3.1415;
const small: f32 = 0.0001;

3. Booleano

  • bool (true ou false)
const is_valid: bool = true;

4. Ponteiros

  • *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

5. Arrays

  • [N]T: array de tamanho fixo
  • []const u8: string (sem null terminator)
const fixed: [3]u8 = .{1, 2, 3};
const str: []const u8 = "Zig!";

6. Enums

  • enum { A, B, C }: mapeia para inteiros
  • Suporta discriminação e introspecção
const State = enum { Idle, Running, Done };
var s: State = State.Idle;

7. Structs

  • struct { x: i32, y: i32 }: agrupamento de campos com tipos definidos
const Vec2 = struct {
    x: f32,
    y: f32,
};

const v = Vec2{ .x = 1.0, .y = 2.0 };

8. Unions

  • union(enum) { A: i32, B: f32 }: tipo com variantes exclusivas
const Value = union(enum) {
    Int: i32,
    Float: f32,
};

var v = Value{ .Int = 10 };

9. Optionals

  • ?T: tipo que pode ser null
const maybe_value: ?i32 = null;
if (maybe_value) |val| {
    std.debug.print("Valor: {}\n", .{val});
}

10. Errors

  • error{Err1, Err2}: enum de erros
  • Usado com !T: retorno que pode ser valor ou erro
const MyError = error{ NotFound };

fn get() !i32 {
    return MyError.NotFound;
}

11. Comptime

  • comptime T: tipo avaliado em tempo de compilação
fn printType(comptime T: type) void {
    std.debug.print("Tipo: {}\n", .{@typeName(T)});
}

12. Anytype

  • Tipo genérico que se adapta automaticamente
fn identity(value: anytype) @TypeOf(value) {
    return value;
}

13. Void e NoReturn

  • void: ausência de valor
  • noreturn: função que nunca retorna (ex: loop infinito ou panic)
fn doNothing() void {}

fn crash() noreturn {
    while (true) {}
}

Exemplos

Usando os tipos em contexto funcional:

Enum com 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);
}

Optional com verificação

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", .{});
    }
}

Criando esse código C++ equivalente em Zig

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.

  • C++:
#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');
}
  • Zig, usando 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", .{});
}
  • O uso de std.ArrayList permite comportamento similar ao std::vector.
  • orderedRemove(index) remove e preserva a ordem (como erase em C++).
  • Strings são tratadas como []const u8 (fatias).
  • O allocator usado é o page_allocator por simplicidade.

Você também poderia usar: std.heap.ArenaAllocator ou lista com []std.BoundedArray.


zig


Compartilhe


Nosso canal no Youtube

Inscreva-se


Marcos Oliveira

Marcos Oliveira

Desenvolvedor de software
https://github.com/terroo


Crie Aplicativos Gráficos para Linux e Windows com C++

Aprenda C++ Moderno e crie Games, Programas CLI, GUI e TUI de forma fácil.

Saiba Mais

Receba as novidades no seu e-mail!

Após cadastro e confirmação do e-mail, enviaremos semanalmente resumos e também sempre que houver novidades por aqui para que você mantenha-se atualizado!