← Zurück zu Lernen

Beispiele

Hello world

A minimal example printing hello world.

hello-world.zig
const std = @import("std");

pub fn main() !void {
    try std.fs.File.stdout().writeAll("hello world!\n");
}
Shell
$ zig build-exe hello-world.zig
$ ./hello-world
hello world!

Aufruf externer Bibliotheks-Funktionen

Alle System-API-Funktionen können auf diese Weise aufgerufen werden, man benötigt keine Bibliotheksbindungen (Wrapper), um sie zu verwenden.

windows-msgbox.zig
const win = @import("std").os.windows;

extern "user32" fn MessageBoxA(?win.HWND, [*:0]const u8, [*:0]const u8, u32) callconv(win.WINAPI) i32;

pub fn main() !void {
    _ = MessageBoxA(null, "world!", "Hello", 0);
}
Shell
$ zig test windows-msgbox.zig
All 0 tests passed.

Erkennung von Speicherlecks

Mit dem std.heap.GeneralPurposeAllocator kann man doppelte Freigaben und Speicherlecks erkennen.

memory-leak.zig
const std = @import("std");

pub fn main() !void {
    var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
    defer std.debug.assert(general_purpose_allocator.deinit() == .ok);

    const gpa = general_purpose_allocator.allocator();

    const u32_ptr = try gpa.create(u32);
    _ = u32_ptr; // silences unused variable error

    // oops I forgot to free!
}
Shell
$ zig build-exe memory-leak.zig
$ ./memory-leak
error(gpa): memory address 0x7f5d08ea0000 leaked:
/home/ci/actions-runner-website/_work/www.ziglang.org/www.ziglang.org/zig-code/samples/memory-leak.zig:9:35: 0x113d457 in main (memory-leak.zig)
    const u32_ptr = try gpa.create(u32);
                                  ^
/home/ci/deps/zig-x86_64-linux-0.15.1/lib/std/start.zig:627:37: 0x113dd49 in posixCallMainAndExit (std.zig)
            const result = root.main() catch |err| {
                                    ^
/home/ci/deps/zig-x86_64-linux-0.15.1/lib/std/start.zig:232:5: 0x113d331 in _start (std.zig)
    asm volatile (switch (native_arch) {
    ^

thread 4088259 panic: reached unreachable code
/home/ci/deps/zig-x86_64-linux-0.15.1/lib/std/debug.zig:559:14: 0x1044179 in assert (std.zig)
    if (!ok) unreachable; // assertion failure
             ^
/home/ci/actions-runner-website/_work/www.ziglang.org/www.ziglang.org/zig-code/samples/memory-leak.zig:5:27: 0x113d526 in main (memory-leak.zig)
    defer std.debug.assert(general_purpose_allocator.deinit() == .ok);
                          ^
/home/ci/deps/zig-x86_64-linux-0.15.1/lib/std/start.zig:627:37: 0x113dd49 in posixCallMainAndExit (std.zig)
            const result = root.main() catch |err| {
                                    ^
/home/ci/deps/zig-x86_64-linux-0.15.1/lib/std/start.zig:232:5: 0x113d331 in _start (std.zig)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)

C-Interoperabilität

Beispiel für den Import einer C-Header-Datei und die Verknüpfung mit libc und raylib.

c-interop.zig
// build with `zig build-exe c-interop.zig -lc -lraylib`
const ray = @cImport({
    @cInclude("raylib.h");
});

pub fn main() void {
    const screenWidth = 800;
    const screenHeight = 450;

    ray.InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
    defer ray.CloseWindow();

    ray.SetTargetFPS(60);

    while (!ray.WindowShouldClose()) {
        ray.BeginDrawing();
        defer ray.EndDrawing();

        ray.ClearBackground(ray.RAYWHITE);
        ray.DrawText("Hello, World!", 190, 200, 20, ray.LIGHTGRAY);
    }
}

Zigg Zagg

Zig ist optimiert für Code-Interviews (nicht wirklich).

ziggzagg.zig
const std = @import("std");

pub fn main() !void {
    var i: usize = 1;
    while (i <= 16) : (i += 1) {
        if (i % 15 == 0) {
            std.log.info("ZiggZagg", .{});
        } else if (i % 3 == 0) {
            std.log.info("Zigg", .{});
        } else if (i % 5 == 0) {
            std.log.info("Zagg", .{});
        } else {
            std.log.info("{d}", .{i});
        }
    }
}
Shell
$ zig build-exe ziggzagg.zig
$ ./ziggzagg
info: 1
info: 2
info: Zigg
info: 4
info: Zagg
info: Zigg
info: 7
info: 8
info: Zigg
info: Zagg
info: 11
info: Zigg
info: 13
info: 14
info: ZiggZagg
info: 16

Generische Typen

In Zig sind Typen zur Kompilierzeit bekannte Werte (comptime values) und wir verwenden Funktionen, die einen Typ zurückgeben, um generische Algorithmen und Datenstrukturen zu implementieren. In diesem Beispiel implementieren wir eine einfache generische Warteschlange und testen ihr Verhalten.

generic-type.zig
const std = @import("std");

pub fn Queue(comptime Child: type) type {
    return struct {
        const Self = @This();
        const Node = struct {
            data: Child,
            next: ?*Node,
        };
        gpa: std.mem.Allocator,
        start: ?*Node,
        end: ?*Node,

        pub fn init(gpa: std.mem.Allocator) Self {
            return Self{
                .gpa = gpa,
                .start = null,
                .end = null,
            };
        }
        pub fn enqueue(self: *Self, value: Child) !void {
            const node = try self.gpa.create(Node);
            node.* = .{ .data = value, .next = null };
            if (self.end) |end| end.next = node //
            else self.start = node;
            self.end = node;
        }
        pub fn dequeue(self: *Self) ?Child {
            const start = self.start orelse return null;
            defer self.gpa.destroy(start);
            if (start.next) |next|
                self.start = next
            else {
                self.start = null;
                self.end = null;
            }
            return start.data;
        }
    };
}

test "queue" {
    var int_queue = Queue(i32).init(std.testing.allocator);

    try int_queue.enqueue(25);
    try int_queue.enqueue(50);
    try int_queue.enqueue(75);
    try int_queue.enqueue(100);

    try std.testing.expectEqual(int_queue.dequeue(), 25);
    try std.testing.expectEqual(int_queue.dequeue(), 50);
    try std.testing.expectEqual(int_queue.dequeue(), 75);
    try std.testing.expectEqual(int_queue.dequeue(), 100);
    try std.testing.expectEqual(int_queue.dequeue(), null);

    try int_queue.enqueue(5);
    try std.testing.expectEqual(int_queue.dequeue(), 5);
    try std.testing.expectEqual(int_queue.dequeue(), null);
}
Shell
$ zig test generic-type.zig
1/1 generic-type.test.queue...OK
All 1 tests passed.

Verwenden von cURL aus Zig

curl.zig
// compile with `zig build-exe zig-curl-test.zig --library curl --library c $(pkg-config --cflags libcurl)`
const std = @import("std");
const cURL = @cImport({
    @cInclude("curl/curl.h");
});

pub fn main() !void {
    var arena_state = std.heap.ArenaAllocator.init(std.heap.c_allocator);
    defer arena_state.deinit();

    const allocator = arena_state.allocator();

    // global curl init, or fail
    if (cURL.curl_global_init(cURL.CURL_GLOBAL_ALL) != cURL.CURLE_OK)
        return error.CURLGlobalInitFailed;
    defer cURL.curl_global_cleanup();

    // curl easy handle init, or fail
    const handle = cURL.curl_easy_init() orelse return error.CURLHandleInitFailed;
    defer cURL.curl_easy_cleanup(handle);

    var response_buffer = std.ArrayList(u8).init(allocator);

    // superfluous when using an arena allocator, but
    // important if the allocator implementation changes
    defer response_buffer.deinit();

    // setup curl options
    if (cURL.curl_easy_setopt(handle, cURL.CURLOPT_URL, "https://ziglang.org") != cURL.CURLE_OK)
        return error.CouldNotSetURL;

    // set write function callbacks
    if (cURL.curl_easy_setopt(handle, cURL.CURLOPT_WRITEFUNCTION, writeToArrayListCallback) != cURL.CURLE_OK)
        return error.CouldNotSetWriteCallback;
    if (cURL.curl_easy_setopt(handle, cURL.CURLOPT_WRITEDATA, &response_buffer) != cURL.CURLE_OK)
        return error.CouldNotSetWriteCallback;

    // perform
    if (cURL.curl_easy_perform(handle) != cURL.CURLE_OK)
        return error.FailedToPerformRequest;

    std.log.info("Got response of {d} bytes", .{response_buffer.items.len});
    std.debug.print("{s}\n", .{response_buffer.items});
}

fn writeToArrayListCallback(data: *anyopaque, size: c_uint, nmemb: c_uint, user_data: *anyopaque) callconv(.C) c_uint {
    var buffer: *std.ArrayList(u8) = @alignCast(@ptrCast(user_data));
    var typed_data: [*]u8 = @ptrCast(data);
    buffer.appendSlice(typed_data[0 .. nmemb * size]) catch return 0;
    return nmemb * size;
}