Introdução a Zig - Parte 4

Estruturas de repetição

Enzo Soares

Publicado em 23 de Março de 2025 às 15:28

Aloha! O tema de hoje são as estruturas de repetição, que nos permitem repetir uma mesma expressão por uma quantidade determinada de tempo ou enquanto uma condição for verdadeira. Zig suporta duas diferentes: o for e o while.

while

O while executa o mesmo pedaço de código enquanto a condição determinada for verdadeira:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) {
        print("{d}\n", .{i});
        i += 1;
    }
}

A saída do código acima é uma sequência de 0 a 9, já que a estrutura de repetição foi executada 10 vezes. A linha i += 1; impede a estrutura de se repetir infinitamente, já que ela garante que i eventualmente chege em 10. Esse padrão é tão importante que Zig nos fornece uma sintaxe própria para ele:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) : (i += 1) {
        print("{d}\n", .{i});
    }
}

Observe o (i += 1) na declaração do while.

Com frequência, é importante interromper a execução da repetição antes do tempo. Para isso, é usada a palavra break:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) : (i += 1) {
        if (i == 5) {
            break;
        }
        print("{d}\n", .{i});
    }
}

O código acima só exibe como saída a sequência de 0 a 4.

Se quisermos pular a execução do resto de uma iteração da estrutura, usamos continue:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) : (i += 1) {
        if (i == 5) {
            continue;
        }
        print("{d}\n", .{i});
    }
}

Na saída, agora, temos uma sequência de 0 a 9, saltando o 5.

É possível colocar a palavra else ao final de um while, que é usado quando a condição da repetição se tornar falsa:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) : (i += 1) {
        print("{d}\n", .{i});
    } else {
        print("Finalizado\n", .{});
    }
}

É exibido na saída uma sequência de 0 a 9, seguido por "Finalizado".

while(true)

Um padrão comum no desenvolvimento de software é executar alguma ação indefinidamente. Imagine que você está lendo um arquivo de texto para procurar a primeira aparição da sequência Zig. A interação tem duração inprevisível. Para isso, podemos usar o while(true) com break.

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var cursor: u8 = 0;
    const test_input = "Eu amo Zig, e não é pouco";

    while (true) : (cursor += 1) {
        if (isZig(test_input[cursor..cursor+3])) {
            break;
        }
    }
}

for

for nos permite operar sobre arrays e fatias de forma mais simples, sem precisar acessar valores através do index:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    const items = [_]i32{ 4, 5, 3, 4, 0 };
    var sum: i32 = 0;

    for (items) |value| {
        sum += value;
    }

    print("{d}",  .{sum});
}

Dentro do for, value é uma variável do tipo i32 que possui o valor armazenado na posição correspondente do array items. É uma forma diferente de escrever:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    const items = [_]i32{ 4, 5, 3, 4, 0 };
    var count: usize = 0;
    var sum: i32 = 0;

    while (items.len > count) : (count += 1) {
        sum += items[count];
    }

    print("{d}",  .{sum});
}

Como fatias de array também são alvos válidos para o for, a sintaxe abaixo é válida, para acessar apenas o 3 primeiros elementos:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    const items = [_]i32{ 4, 5, 3, 4, 0 };
    var sum: i32 = 0;

    for (items[0..2]) |value| {
        sum += value;
    }

    print("{d}",  .{sum});
}

Se, durante a execução do for, for importante ter acesso ao index da execução, é possível usar a sintaxe:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    const items = [_]i32{ 4, 5, 3, 4, 0 };
    var sum: i32 = 0;

    for (items, 0..) |value, index| {
        sum += value;
        print("{d}={d}\n",  .{value, index});
    }

    print("{d}",  .{sum});
}

Para iterar sobre uma sequência de inteiros, a notação de fatia é útil mais uma vez:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var sum: i32 = 0;

    for (0..10) |value| {
        sum += @intCast(value);
    }

    print("{d}",  .{sum});
}

Isso é tudo para nossa introdução a estruturas de repetição. O assunto é mais profundo do que isso, mas foge do escopo de uma introdução. Até a próxima!