Hello World
hello.zig
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, {s}!\n", .{"world"});
}
Shell
$ zig build-exe hello.zig
$ ./hello
Hello, world!
The Zig code sample above demonstrates one way to create a program that will output: Hello, world!.
The code sample shows the contents of a file named hello.zig
. Files storing Zig source code are UTF-8 encoded text files. The files storing Zig source code are usually named with the _.zig_
extension.
Following the hello.zig
Zig code sample, the Zig Build System is used to build an executable program from the hello.zig
source code. Then, the hello
program is executed showing its output Hello, world!. The lines beginning with $ represent command line prompts and a command. Everything else is program output.
The code sample begins by adding the Zig Standard Library to the build using the @import builtin function. The @import("std")
function call creates a structure that represents the Zig Standard Library. The code then declares a constant identifier, named std
, that gives access to the features of the Zig Standard Library.
Next, a public function, pub fn
, named main
is declared. The main
function is necessary because it tells the Zig compiler where the start of the program exists. Programs designed to be executed will need a pub fn main
function.
For more advanced use cases, Zig offers other features to inform the compiler where the start of the program exists. Also, libraries do not need a pub fn main
function because library code is called by other programs or libraries.
A function is a block of any number of statements and expressions that, as a whole, perform a task. Functions may or may not return data after they are done performing their task. If a function cannot perform its task, it might return an error. Zig makes all of this explicit.
In the hello.zig
code sample, the main
function is declared with the !void
return type. This return type is known as an Error Union Type. This syntax tells the Zig compiler that the function will either return an error or a value. An error union type combines an Error Set Type and any other data type (e.g. a Primitive Type or a user-defined type such as a struct, enum, or union). The full form of an error union type is <error set type>``!``<any data type>
. In the code sample, the error set type is not explicitly written on the left side of the !
operator. When written this way, the error set type is an inferred error set type. The void
after the !
operator tells the compiler that the function will not return a value under normal circumstances (i.e. when no errors occur).
Note to experienced programmers: Zig also has the boolean operator !a
where a
is a value of type bool
. Error union types contain the name of the type in the syntax: !``<any data type>
.
In Zig, a function’s block of statements and expressions are surrounded by an open curly-brace {
and close curly-brace }
. Inside of the main
function are expressions that perform the task of outputting Hello, world! to standard output.
First, a constant identifier, stdout
, is initialized to represent standard output’s writer. Then, the program tries to print the Hello, world! message to standard output.
Functions sometimes need information to perform their task. In Zig, information is passed to functions between an open parenthesis (
and a close parenthesis )
placed after the function’s name. This information is also known as arguments. When there are multiple arguments passed to a function, they are separated by commas ,
.
The two arguments passed to the stdout.print()
function, "Hello, {s}!\n"
and .{"world"}
, are evaluated at compile-time. The code sample is purposely written to show how to perform string substitution in the print
function. The curly-braces inside of the first argument are substituted with the compile-time known value inside of the second argument (known as an anonymous struct literal). The \n
inside of the double-quotes of the first argument is the escape sequence for the newline character. The try expression evaluates the result of stdout.print
. If the result is an error, then the try
expression will return from main
with the error. Otherwise, the program will continue. In this case, there are no more statements or expressions left to execute in the main
function, so the program exits.
In Zig, the standard output writer’s print
function is allowed to fail because it is actually a function defined as part of a generic Writer. Consider a generic Writer that represents writing data to a file. When the disk is full, a write to the file will fail. However, we typically do not expect writing text to the standard output to fail. To avoid having to handle the failure case of printing to standard output, you can use alternate functions: the functions in std.log
for proper logging or the std.debug.print
function. This documentation will use the latter option to print to standard error (stderr) and silently return on failure. The next code sample, hello_again.zig
demonstrates the use of std.debug.print
.
hello_again.zig
const print = @import("std").debug.print;
pub fn main() void {
print("Hello, world!\n", .{});
}
Shell
$ zig build-exe hello_again.zig
$ ./hello_again
Hello, world!
Note that you can leave off the !
from the return type because std.debug.print
cannot fail.
See also: