Here's some beginner-friendly advice on how to structure your Zig program to keep it readable and maintainable.
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, world!\n", .{});
}
const std = @import("std");
The main function of a program is the entrypoint. The code section above illustrates some minimal "Hello world" program, which prints the text "Hello, world!" to the console and then exits.
In Zig, your entrypoint will be responsible for bootstrapping your entire program. It should set up a program-wide allocator, parse command line arguments, and read environment configuration. Then, it should invoke your "real" program logic while providing it this information.
In pseudocode, your main function will look like the following.
main() {
const allocator = setupAllocator();
const cli_args = parseCliArgs();
const env_data = queryEnvData();
const config = .{ cli_args, env_data };
runProgram(allocator, config);
}
To set up the allocator, use the standard library's DebugAllocator.
var gpa: DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const allocator = gpa.allocator();
Then, to parse cli args, use the standard library's ArgIterator.
var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); // skip exe name _ = args.next(); // todo: actual arg parsing logic...
Then, to query env data, use getEnvVarOwned.
const host = try std.process.getEnvVarOwned(allocator, "APP_HOST"); // ...