Einfach, explizit und nah an der Maschine
Ausführen: Datei hallo.zig speichern und mit zig run hallo.zig ausführen (Zig von ziglang.org).
zig run, zig build-exe, zig test, zig buildconst std = @import("std");, pub fn main() !voidstd.io.getStdOut().writer() und print mit .{ ... }comptime, Allocators und Fehler als Werte sind die Kernideenzig run hallo.zig # übersetzen und starten
zig build-exe hallo.zig # ausführbare Datei erzeugen
zig build-exe -O ReleaseFast hallo.zig # optimiert
zig test datei.zig # Tests ausführen
zig init # Projektgerüst mit build.zig
zig build run # Projekt bauen und startenconst (unveränderlich) und var; ungenutzte Variablen sind Fehleru8, i32, u3); keine impliziten verlustbehafteten Umwandlungen@intCast, @floatFromInt, @intFromFloat; Überlauf: +%, @addWithOverflow?T mit orelse, if (x) |wert| statt Null-Zeigernif, switch und while mit Wert; for (liste, 0..) |x, i|const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const name = "Mia"; // Typ wird erschlossen
var punkte: i32 = 10; // Typ ausdrücklich
punkte += 5;
const alter: u8 = 17;
var undefiniert: i32 = undefined; // bewusst unbelegt
undefiniert = 7;
try out.print("{s} {d} {d} {d}\n", .{ name, punkte, alter, undefiniert });
const a = 7;
const b = 2;
try out.print("{d} {d} {d} {d}\n", .{ a + b, a - b, a * b, @divTrunc(a, b) });
try out.print("{d} {d} {d}\n", .{ a % b, @mod(-7, 3), @rem(-7, 3) });
try out.print("{d:.3} {d}\n", .{ @as(f64, a) / b, std.math.pow(i32, 2, 10) });
}fn name(a: T) R; Parameter sind unveränderlich, Zeiger *T und .*[N]T (feste Länge im Typ), Slices []T (Zeiger + Länge), ++ und ** zur Übersetzungszeit[]const u8; std.mem bietet eql, indexOf, splitScalar, trimstd.fmt.parseInt, bufPrint für Umwandlungenconst std = @import("std");
fn addiere(a: i32, b: i32) i32 {
return a + b;
}
fn fakultaet(n: u64) u64 {
return if (n <= 1) 1 else n * fakultaet(n - 1);
}
fn minmax(liste: []const i32) struct { min: i32, max: i32 } { // anonymes Struct als Rückgabe
var lo = liste[0];
var hi = liste[0];
for (liste) |x| {
if (x < lo) lo = x;
if (x > hi) hi = x;
}
return .{ .min = lo, .max = hi };
}
fn vertausche(a: *i32, b: *i32) void { // Zeiger als Parameter
const t = a.*;
a.* = b.*;
b.* = t;
}
inline fn quadrat(x: anytype) @TypeOf(x) { // anytype: generischer Parameter
return x * x;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d} {d}\n", .{ addiere(2, 3), fakultaet(15) });
const mm = minmax(&[_]i32{ 4, 9, -2, 7 });
try out.print("{d} {d}\n", .{ mm.min, mm.max });
var x: i32 = 1;
var y: i32 = 2;
vertausche(&x, &y);
try out.print("{d} {d}\n", .{ x, y });
try out.print("{d} {d:.2}\n", .{ quadrat(@as(i32, 7)), quadrat(@as(f64, 1.5)) });
}error{...}, E!T, try (weiterreichen), catch (behandeln)if (res) |wert| ... else |err| ... und switch auf Fehlerdefer räumt am Blockende auf, errdefer nur bei Fehlerstd.fs.cwd().createFile/openFile, immer defer datei.close()unreachable abconst std = @import("std");
const RechenFehler = error{
DivisionDurchNull,
NegativeWurzel,
};
fn teile(a: i32, b: i32) RechenFehler!i32 {
if (b == 0) return error.DivisionDurchNull;
return @divTrunc(a, b);
}
fn wurzel(x: f64) RechenFehler!f64 {
if (x < 0) return RechenFehler.NegativeWurzel;
return @sqrt(x);
}
fn berechne(a: i32, b: i32) !i32 {
const q = try teile(a, b); // try: Fehler an den Aufrufer weitergeben
return q * 2;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d}\n", .{try teile(10, 2)});
const r = teile(1, 0) catch |err| blk: { // catch: Fehler behandeln
try out.print("Fehler: {s}\n", .{@errorName(err)});
break :blk -1;
};
try out.print("{d}\n", .{r});
try out.print("{d}\n", .{teile(9, 0) catch 0}); // Standardwert
if (wurzel(-4)) |w| {
try out.print("{d}\n", .{w});
} else |err| {
try out.print("wurzel scheitert: {s}\n", .{@errorName(err)});
}
if (berechne(5, 0)) |_| {
try out.print("kein Fehler\n", .{});
} else |e| switch (e) { // Fehler in switch prüfen
error.DivisionDurchNull => try out.print("durch null!\n", .{}),
else => unreachable,
}
const zahl = std.fmt.parseInt(u8, "300", 10) catch |e| {
try out.print("parseInt: {s}\n", .{@errorName(e)});
return;
};
try out.print("nie erreicht {d}\n", .{zahl});
}struct mit Feldern, Standardwerten und Methoden; enum, getaggte union(enum)alloc/free, create/destroy, deferArrayList, StringHashMap aus der Standardbibliothekconst std = @import("std");
const Punkt = struct {
x: f64,
y: f64 = 0, // Standardwert
fn abstand(self: Punkt) f64 {
return @sqrt(self.x * self.x + self.y * self.y);
}
fn verschiebe(self: *Punkt, dx: f64, dy: f64) void {
self.x += dx;
self.y += dy;
}
const ursprung = Punkt{ .x = 0 }; // Konstante im Struct
fn neu(x: f64, y: f64) Punkt { // "Konstruktor": normale Funktion
return .{ .x = x, .y = y };
}
};
const Farbe = enum { rot, gruen, blau };
const Form = union(enum) { // getaggte Union
kreis: f64,
rechteck: struct { b: f64, h: f64 },
fn flaeche(self: Form) f64 {
return switch (self) {
.kreis => |r| std.math.pi * r * r,
.rechteck => |r| r.b * r.h,
};
}
};
pub fn main() !void {
const out = std.io.getStdOut().writer();
var p = Punkt.neu(3, 4);
try out.print("{d} {d}\n", .{ p.abstand(), Punkt.ursprung.x });
p.verschiebe(1, 1);
try out.print("({d}, {d})\n", .{ p.x, p.y });
try out.print("{any}\n", .{p});
const f: Farbe = .gruen;
try out.print("{s} {d} {any}\n", .{ @tagName(f), @intFromEnum(f), f == .gruen });
switch (f) {
.rot => try out.print("R\n", .{}),
.gruen, .blau => try out.print("nicht rot\n", .{}),
}
const formen = [_]Form{ .{ .kreis = 1 }, .{ .rechteck = .{ .b = 3, .h = 4 } } };
for (formen) |form| try out.print("{d:.2}\n", .{form.flaeche()});
}comptime führt Code zur Übersetzungszeit aus (Tabellen, Generics, Reflection)fn Stapel(comptime T: type) typeanytype und comptime T: type für generische Parametertest "name" { ... } mit std.testing, zig test; std.testing.allocator findet Speicherlecksconst std = @import("std");
fn fib(comptime n: u32) u64 {
return if (n < 2) n else fib(n - 1) + fib(n - 2);
}
const tabelle = blk: { // Tabelle zur Übersetzungszeit berechnen
var t: [10]u32 = undefined;
for (&t, 0..) |*zelle, i| zelle.* = @intCast(i * i);
break :blk t;
};
pub fn main() !void {
const out = std.io.getStdOut().writer();
const f20 = comptime fib(20); // wird vom Compiler berechnet
try out.print("{d} {any}\n", .{ f20, tabelle });
try out.print("{d} {s}\n", .{ tabelle.len, @typeName(@TypeOf(tabelle)) });
inline for (.{ 1, "zwei", 3.5 }) |wert| { // Schleife über verschiedene Typen
try out.print("{any} ({s})\n", .{ wert, @typeName(@TypeOf(wert)) });
}
}@cImport, Cross-Compiling mit -target, zig cc als C-Compilerbuild.zig beschreibt Projekte in Zig; zig build run/testbuild.zig.zonconst std = @import("std");
const c = @cImport({
@cInclude("stdio.h");
@cInclude("stdlib.h");
@cInclude("string.h");
@cInclude("math.h");
});
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d}\n", .{c.abs(-42)});
try out.print("{d:.3}\n", .{c.sqrt(2.0)});
try out.print("{d}\n", .{c.strlen("Hallo")});
const n = c.atoi("1234");
try out.print("{d}\n", .{n + 1});
}std.Thread, Synchronisierung mit Mutextry, catch, defer, comptime, Allocatorsconst std = @import("std");
fn arbeiter(id: usize, ergebnis: *usize) void {
var summe: usize = 0;
for (0..1000) |i| summe += i * id;
ergebnis.* = summe;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
var ergebnisse = [_]usize{0} ** 4;
var threads: [4]std.Thread = undefined;
for (&threads, 0..) |*t, i| {
t.* = try std.Thread.spawn(.{}, arbeiter, .{ i + 1, &ergebnisse[i] });
}
for (threads) |t| t.join();
try out.print("{any}\n", .{ergebnisse});
var mutex = std.Thread.Mutex{};
var zaehler: u32 = 0;
const Helfer = struct {
fn lauf(m: *std.Thread.Mutex, z: *u32) void {
for (0..1000) |_| {
m.lock();
defer m.unlock();
z.* += 1;
}
}
};
var ts: [3]std.Thread = undefined;
for (&ts) |*t| t.* = try std.Thread.spawn(.{}, Helfer.lauf, .{ &mutex, &zaehler });
for (ts) |t| t.join();
try out.print("{d}\n", .{zaehler});
}