7 Punkte von GN⁺ 2025-08-22 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Zig basiert wie Rust auf einer geschweiften Klammern basierten Syntax, verbessert sie jedoch durch einfachere Sprachsemantik und elegantere Syntaxentscheidungen
  • Integer-Literale beginnen unabhängig vom Typ als comptime_int und werden bei der Zuweisung explizit konvertiert, während String-Literale eine kompakte Raw-String-Notation auf Basis von \\ verwenden
  • Record-Literale in der Form .x = 1 machen Feldzuweisungen leichter durchsuchbar, und alle Typen werden konsistent in Präfixnotation dargestellt
  • and und or werden als Schlüsselwörter für den Kontrollfluss verwendet, und bei if- und **loop-**Konstrukten können geschweifte Klammern optional entfallen, wobei der Formatter die Sicherheit gewährleistet
  • Ohne Namespaces wird alles als Ausdruck behandelt, wodurch die Syntax für Typen, Werte und Muster vereinheitlicht wird und Generics, Record-Literale sowie Built-ins (@import, @as usw.) kompakt genutzt werden können

Überblick

  • Zig hat eine Rust ähnliche äußere Form, setzt aber auf eine einfachere Sprachstruktur
  • Beim Syntaxdesign liegt der Fokus auf grep-Freundlichkeit, syntaktischer Konsistenz und der Reduzierung unnötigen visuellen Rauschens

Integer-Literale

const an_integer = 92;  
assert(@TypeOf(an_integer) == comptime_int);  
  
const x: i32 = 92;  
const y = @as(i32, 92);  
  • Alle Integer-Literale haben den Typ comptime_int
  • Bei der Zuweisung an Variablen wird der Typ explizit angegeben oder per @as konvertiert
  • Die Form var x = 92; funktioniert nicht; ein expliziter Typ ist erforderlich

String-Literale

const raw =  
    \\Roses are red  
    \\  Violets are blue,  
    \\Sugar is sweet  
    \\  And so are you.  
    \\  
;  
  • Jede Zeile ist ein eigenes Token, daher gibt es keine Einrückungsprobleme
  • \\ selbst muss nicht escaped werden

Record-Literale

const p: Point = .{  
    .x = 1,  
    .y = 2,  
};  
  • Das Format .x = 1 ist vorteilhaft, um Lesen und Schreiben zu unterscheiden
  • Die Schreibweise .{} grenzt sich von Blöcken ab und wird automatisch in den Ergebnistyp umgewandelt

Typnotation

u32        // Integer  
[3]u32     // Array der Länge 3  
?[3]u32    // nullbares Array  
*const ?[3]u32 // konstanter Zeiger  
  • Alle Typen verwenden Präfixnotation
  • Die Dereferenzierung verwendet Suffixnotation (ptr.*)

Bezeichner

const @"a name with space" = 42;  
  • Verhindert Konflikte mit Schlüsselwörtern oder erlaubt spezielle Namen

Funktionsdeklaration

pub fn main() void {}  
fn add(x: i32, y: i32) i32 {  
    return x + y;  
}  
  • Das Schlüsselwort fn und der Funktionsname stehen zusammen, was die Suche erleichtert
  • Für die Angabe des Rückgabetyps wird kein -> verwendet

Variablendeklaration

const mid = lo + @divFloor(hi - lo, 2);  
var count: u32 = 0;  
  • Verwendet const und var
  • Die Typangabe folgt der Reihenfolge Name: Typ

Kontrollfluss: and/or

while (count > 0 and ascii.isWhitespace(buffer[count - 1])) {  
    count -= 1;  
}  
  • and und or sind Schlüsselwörter für den Kontrollfluss
  • Für Bit-Operationen werden & und | verwendet

if-Anweisung

.direction = if (prng.boolean()) .ascending else .descending;  
  • Klammern sind Pflicht, geschweifte Klammern optional
  • zig fmt garantiert ein sicheres Formatting

Schleifen

for (0..10) |i| {  
    print("{d}\n", .{i});  
} else @panic("loop safety counter exceeded");  
  • Sowohl for als auch while unterstützen einen else-Zweig
  • Iterator und Elementname sind intuitiv angeordnet

Namespaces und Namensauflösung

const std = @import("std");  
const ArrayList = std.ArrayList;  
  • Shadowing von Variablen ist verboten
  • Es gibt weder Namespaces noch Glob-Imports

Alles ist ein Ausdruck

const E = enum { a, b };  
const e: if (true) E else void = .a;  
  • Die Syntax für Typen, Werte und Muster wird vereinheitlicht
  • Ein bedingter Ausdruck kann an einer Typ-Position stehen

Generics

fn ArrayListType(comptime T: type) type {  
    return struct {  
        fn init() void {}  
    };  
}  
  
var xs: ArrayListType(u32) = .init();  
  • Generics werden mit Funktionsaufrufsyntax (Type(T)) ausgedrückt
  • Typargumente sind immer explizit

Built-ins

const foo = @import("./foo.zig");  
const num = @as(i32, 92);  
  • Mit dem Präfix @ werden vom Compiler bereitgestellte Funktionen aufgerufen
  • @import zeigt den Dateipfad eindeutig an
  • Argumente müssen zwingend String-Literale sein

Fazit

  • Zigs Syntax ist ein Beispiel dafür, wie eine Sammlung kleiner Entscheidungen eine gut lesbare Sprache entstehen lässt
  • Wenn die Anzahl der Features sinkt, sinkt auch der Bedarf an Syntax, und die Wahrscheinlichkeit syntaktischer Konflikte nimmt ebenfalls ab
  • Gute Ideen aus bestehenden Sprachen werden übernommen, aber wenn nötig, werden mutig neue Syntaxformen eingeführt

Noch keine Kommentare.

Noch keine Kommentare.