A Zig program is made from declarations.
A declaration gives a name to something. The name may refer to a value, a function, a type, or an imported module.
const std = @import("std");
const count = 10;
pub fn main() void {
std.debug.print("{d}\n", .{count});
}There are three declarations here.
const std = @import("std");This declares the name std.
const count = 10;This declares the name count.
pub fn main() void {
...
}This declares the function main.
A const declaration has this form:
const name = value;The name is fixed. It cannot later be assigned another value.
const n = 3;
n = 4; // errorA var declaration has this form:
var name = value;The name may be assigned another value.
var n = 3;
n = 4;A declaration may also give the type explicitly.
const x: i32 = 10;
var y: i32 = 20;The part after the colon is the type. Here both x and y have type i32, a signed 32-bit integer.
When the type is omitted, Zig infers it from the value.
const x = 10;This is often enough. But explicit types are useful when the exact size matters.
const small: u8 = 255;u8 is an unsigned 8-bit integer. It can hold values from 0 to 255.
A name is visible inside its scope. A scope is a region of code surrounded by braces.
pub fn main() void {
const a = 1;
{
const b = 2;
std.debug.print("{d} {d}\n", .{ a, b });
}
std.debug.print("{d}\n", .{a});
// b is not visible here
}The name a is visible in the whole function after its declaration. The name b is visible only inside the inner block.
Declarations at the top level of a file are file declarations.
const std = @import("std");
const message = "hello";
pub fn main() void {
std.debug.print("{s}\n", .{message});
}The function main can use std and message because they are declared at file scope.
A declaration can be public.
pub const version = 1;pub means the declaration can be used from another file that imports this file. Without pub, the declaration is private to the file.
Function declarations use fn.
fn add(a: i32, b: i32) i32 {
return a + b;
}This declares a function named add. It takes two i32 values and returns an i32.
A public function uses pub fn.
pub fn main() void {
const sum = add(2, 3);
std.debug.print("{d}\n", .{sum});
}Zig does not require declarations to appear before use at file scope. This is valid:
const std = @import("std");
pub fn main() void {
const sum = add(2, 3);
std.debug.print("{d}\n", .{sum});
}
fn add(a: i32, b: i32) i32 {
return a + b;
}The compiler sees the whole file.
Inside a block, declarations are read in order. A local name must be declared before it is used.
pub fn main() void {
const x = 1;
const y = x + 1;
std.debug.print("{d}\n", .{y});
}A name should say what the value means.
const bytes_read = 128;
const max_line_len = 4096;Short names are useful for small local values.
var i: usize = 0;Longer names are better when the value lives longer or carries more meaning.
const input_file_name = "data.txt";A declaration is simple, but it is the main unit of Zig code. You declare names, give them values or definitions, and use those names to build the program.
Exercises:
Declare a constant named
answerwith value42and print it.Declare a variable named
n, set it to1, then assign2, then print it.Write a function
squarethat takes ani32and returns its square.Move
squarebelowmainand verify that the program still compiles.Create an inner block with a local constant, then try to use that constant outside the block.