⚡ Zig Guide LiveUnofficial
✓ Zig 0.17.0-dev.1454+5faa79730On an older Zig?

Assignment

Zig has two ways to introduce a value, and the default is the immutable one.

const std = @import("std");
const expect = std.testing.expect;

test "const and var" {
    const constant: i32 = 5; // may not be reassigned
    var variable: u32 = 5000; // may be reassigned
    variable += 1;

    // The type can be inferred from the value.
    const inferred_constant = @as(i32, 5);
    var inferred_variable = @as(u32, 5000);
    inferred_variable += 1;

    try expect(constant == 5);
    try expect(variable == 5001);
    try expect(inferred_constant == 5);
    try expect(inferred_variable == 5001);
}

test "undefined leaves memory uninitialised" {
    // `undefined` means "I will assign this before I read it". Reading it
    // first is illegal behaviour, not a guaranteed zero.
    var x: i32 = undefined;
    x = 7;
    try expect(x == 7);
}

const unless proven otherwise

const is not a hint: it is enforced. Reassigning a const is a compile error, and so is declaring a var you never mutate. That second rule surprises people coming from C, but it means a var in Zig is a real signal: this changes.

Type annotations are optional when the compiler can infer them. @as(i32, 5) is an explicit cast used here to pin down what would otherwise be an untyped comptime_int.

undefined is a promise, not a value

var x: i32 = undefined;

This says “I will write to this before I read it”. It does not mean zero. Reading x before assigning is illegal behaviour. In a safety-enabled build Zig fills the memory with 0xaa bytes so the mistake is loud rather than silently plausible.