Zig Programming Language: Panduan Lengkap dari Dasar hingga Mahir
Zig adalah bahasa pemrograman systems-level yang menawarkan kinerja tinggi, keamanan memori, dan kesederhanaan tanpa garbage collector. Pelajari comptime, allocators, error handling, dan banyak lagi.
📋 Daftar Isi
1. Pengenalan Zig
Zig adalah bahasa pemrograman systems-level yang dirancang oleh Andrew Kelley pada tahun 2015. Zig hadir sebagai alternatif C yang lebih modern, aman, dan produktif tanpa mengorbankan performa. Bahasa ini tidak memiliki garbage collector, tidak memiliki preprocessor, dan tidak memiliki hidden control flow.
Filosofi utama Zig meliputi:
- Konsistensi — Tidak ada hidden behavior yang bisa mengejutkan programmer
- Kejelasan — Kode harus mudah dibaca dan dipahami
- Performa — Menghasilkan binary yang sangat cepat
- Kesesuaian dengan C — Bisa memanggil kode C langsung tanpa FFI
Zig bukan hanya bahasa baru, tapi juga bisa menjadi "drop-in replacement" untuk compiler C/C++. Zig dapat meng-compile kode C, C++, dan Zig dalam satu proyek menggunakan Zig Build System.
Keunggulan Zig Dibanding Bahasa Lain
| Fitur | Zig | C | Rust | Go |
|---|---|---|---|---|
| Comptime | ✅ Ya | ❌ Preprocessor | ✅ Macros | ❌ |
| C Interop | ✅ Native | - | ⚠️ FFI | ⚠️ CGo |
| Garbage Collector | ❌ Tidak | ❌ Tidak | ❌ Tidak | ✅ Ya |
| Build System | ✅ Terintegrasi | ❌ Eksternal | ✅ Cargo | ✅ Go modules |
| Compile Speed | Cepat | Cepat | Lambat | Cepat |
2. Instalasi dan Setup
Menginstal Zig sangat mudah. Zig tersedia untuk berbagai platform termasuk Windows, macOS, dan Linux.
Instalasi di Berbagai Platform
# Linux / macOS (menggunakan snap) sudo snap install zig --classic --beta # macOS (menggunakan Homebrew) brew install zig # Windows (menggunakan Scoop) scoop install zig # Atau download langsung dari ziglang.org # https://ziglang.org/download/ # Verifikasi instalasi zig version # Output: 0.13.0 (atau versi terbaru)
Setup Editor
Untuk pengalaman coding yang optimal, gunakan extension berikut:
- VS Code — Extension "Zig" oleh ziglang
- Neovim — Plugin zigtools/zls
- Zed — Support Zig built-in
Membuat Proyek Pertama
# Buat proyek baru mkdir hello-zig && cd hello-zig zig init-exe # Struktur proyek akan seperti ini: # hello-zig/ # ├── build.zig # ├── build.zig.zon # └── src/ # └── main.zig # Build dan jalankan zig build run
3. Dasar-Dasar Zig
Mari kita pelajari sintaks dasar Zig mulai dari program "Hello World".
Hello World
const std = @import("std");
pub fn main() void {
std.debug.print("Hello, {s}!\n", .{"World"});
}
Variabel dan Konstanta
Zig membedakan antara variabel (bisa diubah) dan konstanta (tidak bisa diubah):
const std = @import("std");
pub fn main() void {
// Konstanta - tidak bisa diubah
const nama: []const u8 = "BeebaneLabs";
const umur: u32 = 25;
// Variabel - bisa diubah
var skor: i32 = 100;
skor += 50; // OK
// Type inference - Zig bisa mendeteksi tipe secara otomatis
var otomatis = 42; // tipe: comptime_int
var teks = "Halo"; // tipe: *const [4:0]u8
// Underscore untuk membuang nilai
_ = otomatis;
_ = teks;
std.debug.print("Nama: {s}, Umur: {d}, Skor: {d}\n", .{ nama, umur, skor });
}
Operators dan Expressions
const std = @import("std");
pub fn main() void {
// Aritmatika
const a: i32 = 10;
const b: i32 = 3;
const tambah = a + b; // 13
const kurang = a - b; // 7
const kali = a * b; // 30
const bagi = @divExact(a, b); // error jika tidak habis dibagi
const bagi_floor = @divFloor(a, b); // 3
const sisa = @mod(a, b); // 1
// Bitwise operators
const x: u8 = 0b1010;
const y: u8 = 0b1100;
const AND = x & y; // 0b1000 = 8
const OR = x | y; // 0b1110 = 14
const XOR = x ^ y; // 0b0110 = 6
// Saturating arithmetic
const max_u8: u8 = 255;
const saturated = std.math.add(u8, max_u8, 1) catch max_u8;
std.debug.print("Tambah: {d}, Kali: {d}\n", .{ tambah, kali });
std.debug.print("AND: {b}, OR: {b}\n", .{ AND, OR });
_ = bagi;
_ = bagi_floor;
_ = sisa;
_ = XOR;
_ = saturated;
}
Control Flow
const std = @import("std");
pub fn main() void {
// If expressions (bukan statements!)
const nilai: i32 = 85;
const grade = if (nilai >= 90)
"A"
else if (nilai >= 80)
"B"
else if (nilai >= 70)
"C"
else
"D";
std.debug.print("Grade: {s}\n", .{grade});
// While loop
var i: u32 = 0;
var total: u32 = 0;
while (i < 10) : (i += 1) {
total += i;
}
std.debug.print("Total 0-9: {d}\n", .{total});
// For loop dengan range
var jumlah: u32 = 0;
for (0..10) |angka| {
jumlah += angka;
}
std.debug.print("Jumlah: {d}\n", .{jumlah});
// Labeled blocks
const hasil = blk: {
const x = 10;
const y = 20;
break :blk x + y;
};
std.debug.print("Hasil block: {d}\n", .{hasil});
}
Functions
const std = @import("std");
// Fungsi biasa
fn tambah(a: i32, b: i32) i32 {
return a + b;
}
// Fungsi dengan error union
fn bagi(a: f64, b: f64) !f64 {
if (b == 0) return error.DivisionByZero;
return a / b;
}
// Generic functions menggunakan comptime
fn max(comptime T: type, a: T, b: T) T {
return if (a > b) a else b;
}
// Fungsi dengan multiple return values
fn minMax(data: []const i32) struct { min: i32, max: i32 } {
var min_val = data[0];
var max_val = data[0];
for (data[1..]) |val| {
if (val < min_val) min_val = val;
if (val > max_val) max_val = val;
}
return .{ .min = min_val, .max = max_val };
}
pub fn main() !void {
std.debug.print("3 + 5 = {d}\n", .{tambah(3, 5)});
const hasil = try bagi(10.0, 3.0);
std.debug.print("10 / 3 = {d}\n", .{hasil});
std.debug.print("max(10, 20) = {d}\n", .{max(i32, 10, 20)});
const data = [_]i32{ 5, 2, 8, 1, 9, 3 };
const mm = minMax(&data);
std.debug.print("Min: {d}, Max: {d}\n", .{ mm.min, mm.max });
}
4. Tipe Data dan Variabel
Zig memiliki sistem tipe yang sangat ekspresif dan kuat. Berikut adalah tipe-tipe utama di Zig:
Integer Types
const std = @import("std");
pub fn main() void {
// Unsigned integers: u0, u1, u2, ..., u65535
const a: u8 = 255; // 0 sampai 255
const b: u16 = 65535; // 0 sampai 65535
const c: u32 = 4294967295;
const d: u64 = 18446744073709551615;
// Signed integers: i0, i1, i2, ..., i65535
const e: i8 = -128; // -128 sampai 127
const f: i16 = -32768;
const g: i32 = -2147483648;
const h: i64 = -9223372036854775808;
// Arbitrary precision
const besar: u128 = 340282366920938463463374607431768211455;
// Byte type
const byte: u8 = 'A'; // 65
_ = a; _ = b; _ = c; _ = d;
_ = e; _ = f; _ = g; _ = h;
_ = besar; _ = byte;
}
Structs dan Enums
const std = @import("std");
// Struct definition
const Mahasiswa = struct {
nama: []const u8,
nim: u32,
ipk: f32,
// Method (hanya function yang mengambil self sebagai parameter)
fn toString(self: Mahasiswa) void {
std.debug.print("Nama: {s}, NIM: {d}, IPK: {d:.2}\n",
.{ self.nama, self.nim, self.ipk });
}
fn isLulus(self: Mahasiswa) bool {
return self.ipk >= 2.5;
}
};
// Enum
const Warna = enum {
merah,
hijau,
biru,
kuning,
fn toHex(self: Warna) []const u8 {
return switch (self) {
.merah => "#FF0000",
.hijau => "#00FF00",
.biru => "#0000FF",
.kuning => "#FFFF00",
};
}
};
// Tagged union (enum + union)
const Bentuk = union(enum) {
lingkaran: f64,
persegi: f64,
segitiga: struct { alas: f64, tinggi: f64 },
fn luas(self: Bentuk) f64 {
return switch (self) {
.lingkaran => |r| std.math.pi * r * r,
.persegi => |s| s * s,
.segitiga => |t| 0.5 * t.alas * t.tinggi,
};
}
};
pub fn main() void {
const mhs = Mahasiswa{
.nama = "Andi Pratama",
.nim = 2024001,
.ipk = 3.75,
};
mhs.toString();
std.debug.print("Lulus: {}\n", .{mhs.isLulus()});
const warna = Warna.biru;
std.debug.print("Warna: {s}\n", .{warna.toHex()});
const bentuk = Bentuk{ .lingkaran = 5.0 };
std.debug.print("Luas lingkaran: {d:.2}\n", .{bentuk.luas()});
}
Arrays dan Slices
const std = @import("std");
pub fn main() void {
// Fixed-size array
const angka = [_]u32{ 10, 20, 30, 40, 50 };
// Array dengan pattern
const nol = [_]u8{0} ** 10; // 10 elemen bernilai 0
// Multi-dimensional array
const matriks = [3][3]f32{
.{ 1.0, 0.0, 0.0 },
.{ 0.0, 1.0, 0.0 },
.{ 0.0, 0.0, 1.0 },
};
// Slice (pointer + length)
const slice = angka[1..4]; // [20, 30, 40]
// Iterasi dengan for
for (angka, 0..) |nilai, index| {
std.debug.print("angka[{d}] = {d}\n", .{ index, nilai });
}
// Compile-time array manipulation
const kuadrat = comptime blk: {
var result: [5]u32 = undefined;
for (&result, 0..) |*r, i| {
r.* = i * i;
}
break :blk result;
};
std.debug.print("Kuadrat: {any}\n", .{kuadrat});
_ = nol;
_ = matriks;
_ = slice;
}
5. Comptime (Compile-Time Execution)
Comptime adalah fitur unggulan Zig yang memungkinkan eksekusi kode saat compile time. Ini berbeda dari preprocessor di C atau macro di Rust — comptime menjalankan kode Zig yang sama persis dengan runtime code.
Comptime memungkinkan Anda menulis kode generik tanpa runtime overhead. Semua perhitungan dilakukan saat kompilasi, sehingga binary yang dihasilkan sangat efisien.
Comptime Variables dan Expressions
const std = @import("std");
// Compile-time factorial
fn comptimeFactorial(comptime n: u32) u32 {
if (n <= 1) return 1;
return n * comptimeFactorial(n - 1);
}
// Compile-time Fibonacci
fn comptimeFib(comptime n: u32) u32 {
if (n <= 1) return n;
return comptimeFib(n - 1) + comptimeFib(n - 2);
}
pub fn main() void {
// Semua perhitungan ini terjadi saat compile time!
comptime {
const fak_10 = comptimeFactorial(10);
std.debug.assert(fak_10 == 3628800);
const fib_20 = comptimeFib(20);
std.debug.assert(fib_20 == 6765);
}
// Comptime string manipulation
const pesan = comptime blk: {
const angka = 42;
var buf: [100]u8 = undefined;
const len = std.fmt.bufPrint(&buf, "Jawabannya adalah {d}", .{angka}) catch unreachable;
break :blk buf[0..len.len];
};
std.debug.print("{s}\n", .{pesan});
}
Generic Types dengan Comptime
const std = @import("std");
// Generic Stack
fn Stack(comptime T: type, comptime capacity: usize) type {
return struct {
const Self = @This();
items: [capacity]T = undefined,
len: usize = 0,
fn push(self: *Self, item: T) !void {
if (self.len >= capacity) return error.StackOverflow;
self.items[self.len] = item;
self.len += 1;
}
fn pop(self: *Self) ?T {
if (self.len == 0) return null;
self.len -= 1;
return self.items[self.len];
}
fn peek(self: *Self) ?T {
if (self.len == 0) return null;
return self.items[self.len - 1];
}
};
}
pub fn main() !void {
// Stack of integers
var int_stack = Stack(i32, 10){};
try int_stack.push(10);
try int_stack.push(20);
try int_stack.push(30);
while (int_stack.pop()) |val| {
std.debug.print("Pop: {d}\n", .{val});
}
// Stack of strings
var str_stack = Stack([]const u8, 5){};
try str_stack.push("Hello");
try str_stack.push("World");
std.debug.print("Peek: {s}\n", .{str_stack.peek().?});
}
Comptime Type Reflection
const std = @import("std");
fn printStructInfo(comptime T: type) void {
const info = @typeInfo(T);
switch (info) {
.Struct => |s| {
std.debug.print("Struct: {s}\n", .{@typeName(T)});
std.debug.print("Fields: {d}\n", .{s.fields.len});
inline for (s.fields) |field| {
std.debug.print(" - {s}: {s}\n", .{
field.name,
@typeName(field.type),
});
}
},
else => std.debug.print("Bukan struct: {s}\n", .{@typeName(T)}),
}
}
const Config = struct {
host: []const u8,
port: u16,
debug: bool,
max_connections: u32,
};
pub fn main() void {
comptime printStructInfo(Config);
}
6. Memory Allocators
Salah satu fitur paling penting di Zig adalah pendekatannya terhadap manajemen memori. Zig tidak memiliki GC, tetapi menyediakan allocator interface yang fleksibel dan eksplicit.
Di Zig, semua alokasi memori harus melalui allocator yang di-pass secara eksplisit. Ini membuat jejak alokasi memori sangat jelas dan mudah di-debug.
Jenis Allocator
const std = @import("std");
pub fn main() !void {
// 1. General Purpose Allocator (untuk production)
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Alokasi buffer
const buffer = try allocator.alloc(u8, 1024);
defer allocator.free(buffer);
// 2. Arena Allocator (free semua sekaligus)
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_alloc = arena.allocator();
// Banyak alokasi, dealokasi otomatis saat arena_deinit
const data1 = try arena_alloc.alloc(u32, 100);
const data2 = try arena_alloc.alloc(u8, 500);
_ = data1;
_ = data2;
// 3. Fixed Buffer Allocator (stack-allocated)
var buf: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const fba_alloc = fba.allocator();
const msg = try fba_alloc.dupe(u8, "Hello from FBA!");
std.debug.print("{s}\n", .{msg});
// 4. Page Allocator (system page allocator)
const page_alloc = std.heap.page_allocator;
const big_buf = try page_alloc.alloc(u8, 4096);
defer page_alloc.free(big_buf);
std.debug.print("Buffer sizes: {d}, {d}, {d}\n", .{
buffer.len, msg.len, big_buf.len,
});
}
Dynamic Arrays dengan Allocator
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// ArrayList - dynamic array
var list = std.ArrayList(i32).init(allocator);
defer list.deinit();
// Tambah elemen
for (0..100) |i| {
try list.append(@intCast(i * i));
}
std.debug.print("Jumlah elemen: {d}\n", .{list.items.len});
std.debug.print("Elemen pertama: {d}\n", .{list.items[0]});
std.debug.print("Elemen terakhir: {d}\n", .{list.items[list.items.len - 1]});
// HashMap
var map = std.StringHashMap(u32).init(allocator);
defer map.deinit();
try map.put("apel", 5);
try map.put("jeruk", 3);
try map.put("mangga", 8);
if (map.get("apel")) |jumlah| {
std.debug.print("Jumlah apel: {d}\n", .{jumlah});
}
// Iterasi HashMap
var iter = map.iterator();
while (iter.next()) |entry| {
std.debug.print(" {s}: {d}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
}
}
7. Error Handling
Zig menggunakan error unions untuk error handling — pendekatan yang lebih eksplisit dibanding exception di bahasa lain.
Error Unions
const std = @import("std");
// Custom error set
const FileError = error{
NotFound,
PermissionDenied,
DiskFull,
InvalidPath,
};
// Error union return type
fn readFile(path: []const u8) FileError![]const u8 {
if (path.len == 0) return error.InvalidPath;
if (std.mem.eql(u8, path, "/secret")) return error.PermissionDenied;
if (std.mem.eql(u8, path, "/missing")) return error.NotFound;
return "file contents here";
}
// try operator - propagate error
fn processFile(path: []const u8) !void {
const content = try readFile(path);
std.debug.print("Content: {s}\n", .{content});
}
// catch operator - handle error
fn safeRead(path: []const u8) void {
const content = readFile(path) catch |err| {
std.debug.print("Error: {}\n", .{err});
return;
};
std.debug.print("Content: {s}\n", .{content});
}
// Error union dengan switch
fn handleResult(result: FileError![]const u8) void {
if (result) |content| {
std.debug.print("Success: {s}\n", .{content});
} else |err| {
switch (err) {
error.NotFound => std.debug.print("File tidak ditemukan\n", .{}),
error.PermissionDenied => std.debug.print("Akses ditolak\n", .{}),
error.DiskFull => std.debug.print("Disk penuh\n", .{}),
error.InvalidPath => std.debug.print("Path tidak valid\n", .{}),
}
}
}
pub fn main() void {
safeRead("/valid/path");
safeRead("/missing");
safeRead("/secret");
safeRead("");
}
Error Handling Patterns
const std = @import("std");
fn parseU32(input: []const u8) !u32 {
return std.fmt.parseInt(u32, input, 10) catch return error.ParseError;
}
fn validateAge(input: []const u8) !u8 {
const age = parseU32(input) orelse return error.ParseError;
if (age > 150) return error.InvalidAge;
return @intCast(age);
}
// Error set merging
const AppError = FileError || error{OutOfMemory};
const FileError = error{
FileNotFound,
InvalidFormat,
};
pub fn main() void {
// orelse - unwrap atau default
const val = parseU32("42") orelse 0;
std.debug.print("Value: {d}\n", .{val});
// catch dengan default
const safe_val = parseU32("abc") catch 0;
std.debug.print("Safe value: {d}\n", .{safe_val});
// errdefer - cleanup saat error
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const data = allocator.alloc(u8, 100) catch |err| {
std.debug.print("Alokasi gagal: {}\n", .{err});
return;
};
defer allocator.free(data);
std.debug.print("Alokasi berhasil: {d} bytes\n", .{data.len});
_ = val;
_ = safe_val;
}
8. Build System
Zig memiliki build system terintegrasi yang ditulis dalam Zig sendiri. Ini menggantikan kebutuhan akan Make, CMake, atau build tools lainnya.
Konfigurasi build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
// Standard target options
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Executable
const exe = b.addExecutable(.{
.name = "my-app",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
// Run step
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Unit tests
const unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
Menambah Dependencies
// build.zig.zon - file dependencies Zig
.{
.name = "my-app",
.version = "0.1.0",
.dependencies = .{
.@"zig-network" = .{
.url = "https://github.com/MasterQ32/zig-network/archive/refs/heads/master.tar.gz",
.hash = "1220abc...",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}
Cross Compilation
# Compile untuk Linux x86_64 zig build -Dtarget=x86_64-linux-gnu # Compile untuk Windows zig build -Dtarget=x86_64-windows-gnu # Compile untuk macOS ARM zig build -Dtarget=aarch64-macos # Compile untuk WebAssembly zig build -Dtarget=wasm32-wasi # Compile dengan optimasi zig build -Doptimize=ReleaseFast zig build -Doptimize=ReleaseSafe zig build -Doptimize=ReleaseSmall zig build -Doptimize=Debug
9. C Interop
Salah satu keunggulan terbesar Zig adalah kemampuannya untuk langsung memanggil kode C tanpa FFI wrapper. Zig bahkan bisa meng-include header file C secara langsung.
Menggunakan C Libraries
const c = @cImport({
@cInclude("stdio.h");
@cInclude("math.h");
@cInclude("string.h");
});
const std = @import("std");
pub fn main() void {
// Memanggil C functions langsung
_ = c.printf("Hello from C printf: %d\n", 42);
// Menggunakan C math library
const result = c.sqrt(144.0);
std.debug.print("sqrt(144) = {d}\n", .{result});
// Menggunakan C string functions
var buf: [100]u8 = undefined;
_ = c.strcpy(&buf, "Hello from C!");
_ = c.strcat(&buf, " Concatenated!");
std.debug.print("String: {s}\n", .{buf});
// Menggunakan sin, cos, tan dari C math
const angle: f64 = std.math.pi / 4.0; // 45 degrees
std.debug.print("sin(45°) = {d}\n", .{c.sin(angle)});
std.debug.print("cos(45°) = {d}\n", .{c.cos(angle)});
}
Memanggil Zig dari C
// Fungsi ini bisa dipanggil dari C
export fn zig_add(a: i32, b: i32) i32 {
return a + b;
}
// Fungsi dengan calling convention C
export fn zig_greet(name: [*:0]const u8) void {
const std = @import("std");
std.debug.print("Halo, {s}!\n", .{name});
}
// Struct yang compatible dengan C
export const Point = extern struct {
x: f64,
y: f64,
};
export fn zig_distance(p1: Point, p2: Point) f64 {
const dx = p1.x - p2.x;
const dy = p1.y - p2.y;
return @sqrt(dx * dx + dy * dy);
}
10. Concurrency di Zig
Zig menyediakan primitive concurrency yang rendah-level dan fleksibel tanpa runtime yang berat.
Threads
const std = @import("std");
var counter: u32 = 0;
var mutex = std.Thread.Mutex{};
fn worker(id: u32) void {
var i: u32 = 0;
while (i < 1000) : (i += 1) {
mutex.lock();
counter += 1;
mutex.unlock();
}
std.debug.print("Worker {d} selesai\n", .{id});
}
pub fn main() !void {
// Buat beberapa threads
var threads: [4]std.Thread = undefined;
for (&threads, 0..) |*t, i| {
t.* = try std.Thread.spawn(.{}, worker, .{@as(u32, @intCast(i))});
}
// Tunggu semua threads selesai
for (&threads) |*t| {
t.join();
}
std.debug.print("Counter final: {d}\n", .{counter});
}
Channels (simplified)
const std = @import("std");
// Atomic operations
var shared_value: u32 = 0;
var done: std.atomic.Value(bool) = std.atomic.Value(bool).init(false);
fn producer() void {
var i: u32 = 0;
while (i < 10) : (i += 1) {
shared_value = i;
std.debug.print("Produced: {d}\n", .{i});
std.time.sleep(100_000_000); // 100ms
}
done.store(true, .seq_cst);
}
fn consumer() void {
while (!done.load(.seq_cst)) {
std.debug.print("Consumed: {d}\n", .{shared_value});
std.time.sleep(150_000_000); // 150ms
}
}
pub fn main() !void {
const producer_thread = try std.Thread.spawn(.{}, producer, .{});
const consumer_thread = try std.Thread.spawn(.{}, consumer, .{});
producer_thread.join();
consumer_thread.join();
}
11. Proyek Praktis: HTTP Server Sederhana
Mari kita buat HTTP server sederhana menggunakan Zig networking.
const std = @import("std");
const Response = struct {
status: u16,
body: []const u8,
fn format(self: Response, allocator: std.mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator,
\\HTTP/1.1 {d} OK
\\Content-Type: text/html; charset=utf-8
\\Content-Length: {d}
\\Connection: close
\\
\\{s}
, .{ self.status, self.body.len, self.body });
}
};
const html_page =
\\<!DOCTYPE html>
\\<html>
\\<head><title>Zig Server</title></head>
\\<body>
\\<h1>Hello from Zig!</h1>
\\<p>Server ini ditulis dalam bahasa Zig.</p>
\\</body>
\\</html>
;
fn handleClient(client: std.net.StreamServer.Connection) void {
defer client.stream.close();
var buf: [1024]u8 = undefined;
const n = client.stream.read(&buf) catch return;
const request = buf[0..n];
std.debug.print("Request: {s}\n", .{request[0..@min(n, 100)]});
const response = Response{
.status = 200,
.body = html_page,
};
const formatted = response.format(std.heap.page_allocator) catch return;
_ = client.stream.write(formatted) catch return;
}
pub fn main() !void {
const address = try std.net.Address.parseIp("127.0.0.1", 8080);
var server = try address.listen(.{
.reuse_address = true,
});
defer server.deinit();
std.debug.print("Server berjalan di http://127.0.0.1:8080\n", .{});
while (true) {
const client = try server.accept();
// Handle each connection (single-threaded for simplicity)
handleClient(client);
}
}
Testing
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
fn fibonacci(n: u32) u32 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
test "fibonacci basic cases" {
try expectEqual(fibonacci(0), 0);
try expectEqual(fibonacci(1), 1);
try expectEqual(fibonacci(2), 1);
try expectEqual(fibonacci(10), 55);
try expectEqual(fibonacci(20), 6765);
}
test "array operations" {
var list = std.ArrayList(i32).init(std.testing.allocator);
defer list.deinit();
try list.append(1);
try list.append(2);
try list.append(3);
try expectEqual(list.items.len, 3);
try expectEqual(list.items[0], 1);
try expectEqual(list.items[2], 3);
}
🧠 Kuis: Zig Programming Language
Uji pemahaman Anda tentang Zig dengan 5 pertanyaan berikut: