Skip to main content

Primitive Types

Zig provides a rich set of primitive types for various use cases.

Integer Types

Integer literals can be written in multiple formats:
const decimal_int = 98222;
const hex_int = 0xff;
const another_hex_int = 0xFF;
const octal_int = 0o755;
const binary_int = 0b11110000;

// underscores may be placed between two digits as a visual separator
const one_billion = 1_000_000_000;
const binary_mask = 0b1_1111_1111;
const permissions = 0o7_5_5;
const big_address = 0xFF80_0000_0000_0000;
Signed integers are represented with i followed by the bit count:
  • i8, i16, i32, i64, i128
  • isize - pointer-sized signed integer
const x: i32 = -42;
const y: i8 = -128;

Floating-Point Types

Zig supports standard floating-point types:
const floating_point = 123.0E+77;
const another_float = 123.0;
const yet_another = 123.0e+77;

const hex_floating_point = 0x103.70p-5;
const another_hex_float = 0x103.70;
const yet_another_hex_float = 0x103.70P-5;

// underscores may be placed between two digits as a visual separator
const lightspeed = 299_792_458.000_000;
const nanosecond = 0.000_000_001;
const more_hex = 0x1234_5678.9ABC_CDEFp-10;
Available floating-point types:
  • f16 - 16-bit float
  • f32 - 32-bit float
  • f64 - 64-bit float
  • f80 - 80-bit float
  • f128 - 128-bit float

Boolean Type

The boolean type bool has two values: true and false:
const is_valid: bool = true;
const is_error: bool = false;

String Type

Strings in Zig are UTF-8 encoded byte arrays:
const print = @import("std").debug.print;
const mem = @import("std").mem;

pub fn main() void {
    const bytes = "hello";
    print("{}\n", .{@TypeOf(bytes)}); // *const [5:0]u8
    print("{d}\n", .{bytes.len}); // 5
    print("{c}\n", .{bytes[1]}); // 'e'
    print("{d}\n", .{bytes[5]}); // 0
    print("{}\n", .{'e' == '\x65'}); // true
    print("{d}\n", .{'\u{1f4a9}'}); // 128169
    print("{d}\n", .{'💯'}); // 128175
    print("{u}\n", .{'⚡'});
    print("{}\n", .{mem.eql(u8, "hello", "h\x65llo")}); // true
    print("{}\n", .{mem.eql(u8, "💯", "\xf0\x9f\x92\xaf")}); // true
}
String literals are null-terminated ([N:0]u8) for C interoperability.

Type Inference

Zig can infer types from the initialization expression:
const x = 10; // type inferred as comptime_int
const y: u32 = 10; // explicitly typed as u32
const a = 5; // comptime_int
const b = 3.14; // comptime_float
const c = "hello"; // *const [5:0]u8

Optional Types

Optional types are denoted with ? and can hold either a value or null:
const expect = @import("std").testing.expect;

test "optional type" {
    // Declare an optional and coerce from null:
    var foo: ?i32 = null;

    // Coerce from child type of an optional
    foo = 1234;

    // Use compile-time reflection to access the child type of the optional:
    try comptime expect(@typeInfo(@TypeOf(foo)).optional.child == i32);
}
Optionals are commonly used instead of null pointers to represent the absence of a value safely.

Type Coercion

Zig performs type coercion in specific cases:
Smaller integer types automatically coerce to larger ones:
const a: u8 = 250;
const b: u16 = a; // OK - u8 coerces to u16

Type Reflection

Zig provides compile-time type introspection with @TypeOf and @typeInfo:
const x = 10;
const T = @TypeOf(x); // gets the type of x
Explicit type casting may be required when automatic coercion doesn’t apply. Use @intCast, @floatCast, @ptrCast, etc.

Void Type

The void type has exactly one value and is used for functions that don’t return anything:
fn doNothing() void {
    // no return value
}

NoReturn Type

The noreturn type indicates a function never returns:
fn abort() noreturn {
    @branchHint(.cold);
    while (true) {}
}
Use noreturn for functions that exit the program, loop forever, or always panic.

Build docs developers (and LLMs) love