zigで配列を扱いたい~配列、for文、スライス~

zig

環境

当方の環境は以下である。
zig version: 0.16.0
Windows 11 + x86_64 + wsl2 + ubuntu24.04 + zsh

配列

配列は以下のように宣言する。

constかvar 識別子 = [要素数Nか_]型{1要素目,2要素目,・・・N要素目};
例:var arr = [_]u8{0,1,2,3,4,5,6,7};

各要素は以下のように取得する。

変数 = 識別子[要素数];
例:arr01 = arr[0];

要素数は以下のように取得する。

変数 = 識別子.len;
例:arrlen = arr.len;

複数配列の連結も以下のように取得可能である。

変数 = 配列 ++ 配列 ・・・ ++ 配列;
例:arrall = arrsub01 ++ arrsub02 ++ arrsub03;

複数回繰り返しのある配列は以下のように取得できる。

変数 = 配列 ** 繰り返し数
例:arru32bit = arru4bit ** 8;

配列は分解することも可能である。

1要素目の変数, 2要素目の変数,・・・N要素目の変数 = 配列
例:arrrev00, _, const arrrev02 = arrrev;

複数次元を持つこともできる。

例:var matrix: [2][3]u8{
    [_]u8{1,0,0},
    [_]u8{0,1,0},
}

センチネル要素を持つ配列を宣言することもできるが、詳細は文字列について取り上げるときに言及することとする。

for文

Cでは繰り返しのイメージだったが、zigにおけるfor文はイテレーションのための構文である。

for文で各要素を要素順に取得することが可能である。

for (配列) |イテレータを格納する識別子| {}
例:for (arr) |n| {
        print("{}\n", .{n});
    }

インデックス用、すなわちusizeのイテレータを範囲指定することも可能である。初期値から+1ずつされていく。初期値より最終値を低くしても-1ずつされることはなくエラーとなる。

for (初期値..最終値+1) |イテレータを格納する識別子| {}
例:for (0..N) |i| {
        print("{}\n", .{arr[i]});
  }

配列とインデックスを同時に取得することも可能である。

for (配列, 初期値..) |識別子, 識別子| {}
例:for (arr, 0..) |n, i| {
        print("arr[{}]:{}\n", .{i, n});
  }

配列をイテレーションし各要素の値を変更したい場合、イテレータはconstであり別物であるため、ポインタを扱うことで実現する。

for (&配列) |*識別子| {}
例:for (&arr) |*n| n.* += 1;
    print("{any}\n", .{arr});

本稿ではとりあえず配列を操作するのに必要なことについて述べるに留め、ラベル付きfor文やインラインfor文についての詳細は別途言及することとする。

スライス

配列の特定範囲の要素を取得したい場合、スライスを使用することで実現できる。終了要素を省略した場合は配列長が適用されるが、開始要素は省略できない。

for (配列[開始要素..終了要素]) |識別子| {}
例:for (arr[1..]) |n| {
        print("{}\n", .{n});
    }

尚、スライスはポインタであり、for文の際は値が格納されるが、分解の際はポインタの値を取得する構文にする必要がある。

S要素目の変数,・・・E要素目の変数 = 配列[開始要素S..終了要素E].*
例:b,c = arr[1..3].*

サンプル実行例

array_for_slice.zig

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

pub fn main(_: std.process.Init) !void {
    print("配列の宣言、要素指定、要素数取得、インデックスを扱うfor文\n", .{});
    var arr: [8]u8 = undefined;
    var arr01: u8 = undefined;
    var arrlen: u8 = undefined;
    arrlen = arr.len;
    for (0..arrlen) |n| arr[n] = @intCast(n); //n: usize
    arr01 = arr[0];
    print("arrlen:{}\n", .{arrlen});
    print("arr:{any}\n", .{arr});
    print("arr01:{}\n", .{arr01});
    print("\n", .{});

    print("配列の連結、配列とインデックスを同時に扱うfor文\n", .{});
    const arrsub01 = [_]u8{ 0, 1 };
    const arrsub02 = [_]u8{ 2, 3 };
    const arrsub03 = [_]u8{ 4, 5, 6, 7 };
    const arrall = arrsub01 ++ arrsub02 ++ arrsub03;
    print("arrsub01:{any}, arrsub02:{any}, arrsub03:{any}\n", .{ arrsub01, arrsub02, arrsub03 });
    print("arrall:{any}\n", .{arrall});
    for (arrall, 0..) |n, i| print("{}要素目: {}{s}", .{ i, n, if (i == arrall.len - 1) "\n" else ", " });
    print("\n", .{});

    print("配列の繰り返し\n", .{});
    var arru4bit: [4]u1 = undefined;
    var arru32bit: [32]u1 = undefined;
    arru4bit = [_]u1{ 1, 1, 1, 1 };
    arru32bit = arru4bit ** 8;
    print("arru4bit:{any}\n", .{arru4bit});
    print("arru32bit:{any}\n", .{arru32bit});
    //print("符号無し整数における2進数->10進数変換\n", .{});
    var uvalue: u64 = 0;
    for (arru32bit) |bit| uvalue = (uvalue << 1) | bit;
    print("uvalue: {}\n", .{uvalue});
    print("\n", .{});

    print("配列の分解とスライス、スライスを扱うfor文\n", .{});
    const arrrev = [_]i8{ 0, -1, -2, -3 };
    var arrrev00: i8 = undefined;
    arrrev00, _, const arrrev02, _ = arrrev;
    print("arrrev:{any}\n", .{arrrev});
    print("arrrev00: {}, arrrev02: {}\n", .{ arrrev00, arrrev02 });
    const s = 1;
    const e = arrrev.len;
    const arrrev01, _, const arrrev03 = arrrev[s..e].*;
    print("arrrev01: {}, arrrev03: {}\n", .{ arrrev01, arrrev03 });
    for (arrrev[s..e], s..) |n, i| print("{}要素目: {}{s}", .{ i, n, if (i == e - 1) "\n" else ", " });
    print("\n", .{});

    print("複数次元を持つ配列とポインタと扱うfor文\n", .{});
    const x = 3;
    const y = 3;
    var matrix: [x][y]u8 = .{.{0} ** y} ** x; //.{}: tuple, a.k.a. anonymous struct
    for (&matrix, 0..) |*row, i| row.*[i] = 1; //iter is const.
    print("matrix:{any}\n", .{matrix});
    print("\n", .{});
}

zsh

zig build-exe -fno-llvm -O ReleaseSafe array_for_slice.zig
% ./array_for_slice
配列の宣言、要素指定、要素数取得、インデックスを扱うfor文
arrlen:8
arr:{ 0, 1, 2, 3, 4, 5, 6, 7 }
arr01:0

配列の連結、配列とインデックスを同時に扱うfor文
arrsub01:{ 0, 1 }, arrsub02:{ 2, 3 }, arrsub03:{ 4, 5, 6, 7 }
arrall:{ 0, 1, 2, 3, 4, 5, 6, 7 }
0要素目: 0, 1要素目: 1, 2要素目: 2, 3要素目: 3, 4要素目: 4, 5要素目: 5, 6要素目: 6, 7要素目: 7

配列の繰り返し、スライスを扱うfor文
arru4bit:{ 1, 1, 1, 1 }
arru32bit:{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
uvalue: 4294967295

配列の分解とスライス、スライスを扱うfor文
arrrev:{ 0, -1, -2, -3 }
arrrev00: 0, arrrev02: -2
arrrev01: -1, arrrev03: -3
1要素目: -1, 2要素目: -2, 3要素目: -3

複数次元を持つ配列とポインタと扱うfor文
matrix:{ { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }

%

本稿はここまでにゅんちゅ!