const and var
Zig has two kinds of variable declarations:
constand
varA const declaration creates a name whose value cannot change.
const year = 2026;A var declaration creates a mutable variable.
var count = 0;The difference is important. Zig prefers immutability when possible.
Consider:
const std = @import("std");
pub fn main() void {
const x = 10;
std.debug.print("{d}\n", .{x});
}This program is correct.
Now try to assign a new value:
const x = 10;
x = 20;The compiler reports an error. A constant cannot be changed after initialization.
A mutable variable may be assigned another value:
const std = @import("std");
pub fn main() void {
var n = 1;
n = 2;
n = 3;
std.debug.print("{d}\n", .{n});
}The output is:
3A declaration must always be initialized.
This is valid:
const x = 5;
var y = 10;This is not:
var n; // errorZig does not allow uninitialized local variables unless the programmer explicitly asks for undefined memory.
var n: i32 = undefined;undefined means the value is not initialized. Reading it before writing a value is an error.
Usually you should initialize variables normally.
var n: i32 = 0;The compiler checks whether a mutable variable is actually mutated.
var x = 10;If x is never changed, the compiler may suggest using const instead.
This helps keep programs simpler and safer.
A constant does not mean the data itself is always immutable. It means the binding cannot be changed.
Consider:
var data = [_]u8{ 1, 2, 3 };
const slice = data[0..];slice always refers to the same slice, but the underlying array may still change.
data[0] = 9;Now slice[0] is also 9.
The constant applies to the name, not necessarily to all reachable memory.
You may also create constant pointers and mutable pointers.
var x: i32 = 10;
const p = &x;p always points to the same location.
But the value at that location may still change:
p.* = 20;The expression:
p.*means “the value pointed to by p”.
A mutable variable is useful when a value changes over time.
var sum: i32 = 0;
sum += 1;
sum += 2;
sum += 3;A constant is useful when a value should stay fixed.
const max_users = 100;Most declarations in Zig programs are constants.
This style has several advantages:
- values cannot change accidentally
- the compiler can reason more precisely
- code is easier to read
- fewer states exist in the program
A small example:
const std = @import("std");
pub fn main() void {
const width = 80;
const height = 25;
const area = width * height;
std.debug.print("{d}\n", .{area});
}None of these values need mutation, so const is appropriate.
Now consider a loop:
const std = @import("std");
pub fn main() void {
var i: usize = 0;
while (i < 5) : (i += 1) {
std.debug.print("{d}\n", .{i});
}
}Here i changes during execution, so it must be declared with var.
Use const by default. Use var only when mutation is necessary.
Exercises:
Declare a constant named
piwith value3.14.Declare a variable named
count, increment it three times, then print it.Write a program that swaps the values of two mutable variables.
Create a mutable array and a constant slice that refers to it. Modify the array and print the slice contents.
Declare a variable with
undefined, assign a value later, then print it.