पाठ 13 / 25
comptime Basics
Run code at compile time and use compile-time parameters.
One language for run time and compile time
Zig's signature feature is comptime: ordinary Zig code can run during compilation. A comptime block or expression is evaluated by the compiler, and its result is embedded in the program: lookup tables, precomputed constants or validated configuration cost nothing at run time. Function parameters marked comptime must be known at compile time, which enables specialisation: the function is instantiated separately for each distinct value. Types are values at compile time (of type type), so they can be passed to functions, stored in constants and returned, which is how Zig implements generics without a separate template language. @compileError reports custom compile errors, perfect for validating assumptions ("this struct must be 64 bytes"). inline for and inline while unroll loops at compile time, for example over a struct's fields. There are limits: comptime code cannot perform I/O or call external functions, and long comptime evaluations need @setEvalBranchQuota. This replaces C's preprocessor macros, C++ templates and many code generators with one consistent language.
Compile time and run time
comptime code runs in the compiler; its results become constants in the binary.
Lookup tables and assertions at compile time
A table computed by the compiler and a size check.
const std = @import("std");
fn fib(n: u64) u64 {
return if (n < 2) n else fib(n - 1) + fib(n - 2);
}
// Computed entirely by the compiler; the binary just contains the array
const fib_table = blk: {
@setEvalBranchQuota(100_000); // naive recursion needs many comptime steps
var table: [20]u64 = undefined;
for (&table, 0..) |*slot, i| slot.* = fib(i);
break :blk table;
};
const Header = extern struct {
magic: u32,
version: u16,
flags: u16,
length: u64,
};
comptime {
if (@sizeOf(Header) != 16) @compileError("Header must be exactly 16 bytes for the file format");
}
fn repeat(comptime n: usize, ch: u8) [n]u8 { // n is part of the return type
var out: [n]u8 = undefined;
@memset(&out, ch);
return out;
}
pub fn main() void {
std.debug.print("fib(19) = {d}\n", .{fib_table[19]}); // 4181, no run-time computation
const line = repeat(10, '=');
std.debug.print("{s}\n", .{&line});
std.debug.print("Header is {d} bytes\n", .{@sizeOf(Header)});
}Compile-time checks are documentation
A comptime assertion about a struct size, an enum count or a configuration value documents an assumption and turns its violation into a build failure instead of a production bug.
त्वरित जाँच: What can a function do with a `comptime T: type` parameter?
- Use T as a type in its body, making the function generic over T
- Nothing; types cannot be parameters
- Change T at run time
- Only print T
Answer
Use T as a type in its body, making the function generic over T — Types are compile-time values, which is how Zig does generics.