An variable in Zig is a name associated with a value having an explicit type and mutability. If you come from JavaScript, Python, or even C, variable management in Zig may seem strict at first.
This rigidity forces us to express whether a value can change from the moment we declare it.
In Zig, we don’t declare a variable and then “see later” if it changes or not. The language forces us to make a design decision when writing the line: will this value change?
This simple question, answered thousands of times throughout a project, eliminates an entire category of bugs related to unexpected state changes.
Declaration Syntax
The basic structure for declaring any data in Zig always follows this pattern:
keyword name: type = value;- keyword: can be
constorvar. - name: the variable identifier (in
snake_caseby convention). - type: The data type (
i32,u8,bool, etc.). - value: The initial value.
In Zig, you must always initialize a variable. There is no concept of “declare now and define later” leaving the memory dirty by default (like in C). If you don’t have a value, you must use undefined explicitly.
Constants: const
In Zig, const is the default option. Use it unless you need to modify the value.
A const variable is immutable. Once assigned, its value can never change during its lifetime scope.
const max_lives: i32 = 5;
const game_name: []const u8 = "Super Zig Bros";
// This would cause a COMPILATION ERROR:
// max_lives = 6; Why prefer const?
- Readability: If you’re reading someone else’s code and see
const, your brain rests. You know that value is reliable and won’t change five lines below. - Optimization: The compiler can perform aggressive optimizations if it knows a value never changes.
Variables: var
We use var only when we have the explicit intention to modify the value. For example, in counters, accumulators, or evolving states.
var counter: i32 = 0;
counter += 1; // This is validType Inference
Zig is a statically typed language (types are fixed at compile time), but it has type inference. This means that, if the context is clear, we can omit the type and let the compiler deduce it.
const number = 42; // The literal retains the comptime_int type
var health: i32 = 100;
health -= 1;Although inference is convenient, it is advisable to be explicit with types when the context does not make them clear. In function signatures, Zig requires indicating the types of parameters and the return type.
The Concept of undefined
What happens if we want to declare a variable (perhaps a large array) without spending time filling it with zeros because we will write all its data immediately after?
In C, you can just declare int a;, whose value is indeterminate. In Zig, you must express that intention using undefined.
var buffer: [100]u8 = undefined;With undefined, we are telling the compiler: “I know this variable has garbage right now. I promise not to read it until I have written something in it.”
Using undefined avoids unnecessary initialization, but reading the value before writing to it is illegal behavior. In Debug mode, Zig may fill that memory with the 0xAA pattern, which helps detect the error during development.
The Unused Variable Rule
This is the feature that frustrates beginners the most.
If you declare a variable in Zig and don’t use it, the program will not compile.
pub fn main() void {
const x: i32 = 50;
// Error: unused local constant 'x'
std.debug.print("Hello", .{});
}Why is it so strict? Because an unused variable is usually a symptom of:
- A bug: You calculated something but forgot to use the result.
- Dead code: You are cluttering the code with unnecessary things.
How to Silence the Error
If you really need to declare something and not use it (for example, you receive a parameter you don’t need), you can assign it to an underscore _:
const ignored_value = 10;
_ = ignored_value; // "We use" the variable by discarding itShadowing Prohibited
Many languages allow declaring a variable with the same name as another in an outer scope.
// JavaScript (allowed)
let x = 10;
{
let x = 5; // Hides the x above
}In Zig, this is a compilation error.
// Zig
const x: i32 = 10;
{
const x: i32 = 5; // Error: redeclaration of local constant 'x'
}Zig prohibits shadowing because it makes code hard to read. If you see x on line 50, you shouldn’t have to scan upward to see “which of the three x” is active. One unique name for each thing.