← Torna a Impara

Esempi

Hello world

Un semplice "ciao mondo".

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!

Chiamare funzioni da librerie esterne

Tutte le funzioni delle API di sistema possono essere invocate in questo modo, non sono necessari binding per interfacciarsi ad esse.

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.

Rilevamento di memory leak

Usando std.heap.GeneralPurposeAllocator puoi tracciare i double free e i memory leak.

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)

Interoperabilità con C

Questo esempio importa un file di intestazione C e fa il link di libc e 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 è ottimizzato per i colloqui tecnici (non proprio).

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

Tipi generici

In Zig i tipi di dato sono valori conosciuti in fase di compilazione, e utilizziamo funzioni che restituiscono tipi per implementare algoritmi generici e strutture dati. In questo esempio implementiamo una semplice coda generica e testiamo il suo funzionamento.

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.

Usare cURL da 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;
}