Lesson 3 / 25
Variables, Types and Integers
Declare constants and variables, use integer and float types, and cast explicitly.
Explicit types, explicit conversions
Declare immutable values with const and mutable ones with var; the compiler reports an error if a var is never mutated or a local is unused (discard with _ = x;). Types can be inferred from the initialiser, but a var usually needs an explicit type: var count: u32 = 0;. Zig has arbitrary bit-width integers: u8, i32, u64, usize (pointer-sized) and even u3 or i7, plus f16, f32, f64 and f128 floats, bool, and comptime-known literals (comptime_int, comptime_float) that have unlimited precision until assigned. Conversions are explicit: widening that cannot lose information coerces automatically (u8 to u32), but narrowing requires @intCast, which is checked in safe modes, and float/integer conversions use @floatFromInt and @intFromFloat. Many cast builtins take their destination type from the result location: const small: u8 = @intCast(big);, or use @as(u8, @intCast(big)). Variables must be initialised; undefined explicitly leaves memory uninitialised (and is filled with a recognisable pattern in Debug builds). Strings literals are constant byte arrays (*const [N:0]u8), usually used as []const u8 slices.
Types and explicit casts
Integer sizes, coercion, checked narrowing and undefined.
const std = @import("std");
pub fn main() void {
const price_paise: u32 = 49_900; // underscores for readability
const qty: u8 = 3;
const total: u64 = price_paise * @as(u32, qty); // u8 coerces to u32; u32 coerces to u64
const big: u32 = 200;
const small: u8 = @intCast(big); // checked: panics in safe modes if big > 255
const avg: f64 = @as(f64, @floatFromInt(total)) / 3.0;
const rounded: u64 = @intFromFloat(@round(avg));
var buffer: [16]u8 = undefined; // intentionally uninitialised
buffer[0] = 'Z';
const tiny: u3 = 7; // a 3-bit unsigned integer (0..7)
const name: []const u8 = "Asha"; // string literal as a slice of bytes
std.debug.print("total={d} small={d} avg={d:.2} rounded={d}\n", .{ total, small, avg, rounded });
std.debug.print("tiny={d} name={s} len={d} first={c}\n", .{ tiny, name, name.len, buffer[0] });
}Unused variables are errors
Zig rejects unused locals and parameters, and vars that are never mutated. It feels strict at first, but it catches real bugs; while experimenting, write _ = value; to acknowledge something on purpose.
Quick check: How do you convert a u32 to a u8 in Zig?
- It happens implicitly
- With a C-style cast (u8)x
- With @intCast, which is checked at run time in safe build modes
- It is impossible
Answer
With @intCast, which is checked at run time in safe build modes — Narrowing conversions require @intCast, which panics on out-of-range values in safe modes.