# Variables, Types and Integers — Zig

Source: https://www.geekswithgeeks.com/en/zig/f-basics

> 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.

```zig
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 `var`s that are never mutated. It feels strict at first, but it catches real bugs; while experimenting, write `_ = value;` to acknowledge something on purpose.

**Quiz:** How do you convert a u32 to a u8 in Zig?

- [ ] It happens implicitly
- [ ] With a C-style cast (u8)x
- [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.
