Zig Basic Syntax

Zig is a new programming language, simple and efficient in design, and directly compatible with the C language.

Below is an introduction to some basic Zig syntax to help you get started quickly.

The file extension for Zig code files is.zig。


First Zig Program

Let's first take a look at Zig's "Hello, World!" program.

Let's first initialize a zig project:

mkdir hello-world
cd hello-world
zig init

Then create the hello.zig file in this project, with the following code:

Example (hello.zig file)

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    try stdout.print("Hello, World!\n", .{});
}

Code analysis:

1. Import the standard library:

const std = @import("std");

This line of code imports Zig's standard library, similar to in the C language.#include <stdio.h>。

2. Define the main function:

pub fn main() !void

pubThe keyword indicates that this function is public,fnThe keyword is used to define a function,mainis the entry point of the function. The return type!voidindicates that the function does not return a value, but may return an error (!prefix indicates an error union type).

3. Get standard output:

const stdout = std.io.getStdOut().writer();

Obtain the standard output writer through the standard library, then call its methods to write content.

4. Print "Hello, World!":

try stdout.print("Hello, World!\n", .{});

printThe method writes the formatted string to standard output,.{}is an empty parameter list.tryThe keyword propagates errors upward to the caller when an error occurs.

This program demonstrates some basic features of the Zig language, such as function definition, use of the standard library, and error handling.

If you just want to run a single file, you can directly use:

zig run hello.zig

If you want to compile it into an executable, use:

zig build-exe hello.zig

After compilation, run it in the terminal:

./hello

This will output:

Hello, World!

Identifiers

In Zig, identifiers are names used to name variables, functions, types, and so on.

Here are some rules and features regarding Zig identifiers:

  1. Letters and Digits: Identifiers can contain letters (A-Z and a-z), digits (0-9), and underscores (_).

  2. Starting Character: Identifiers must start with a letter or underscore, and cannot start with a digit.

  3. Case Sensitivity: Zig is a case-sensitive language, which meansVariableandvariableare two different identifiers.

  4. Keywords and Reserved Words: Some specific words are reserved in Zig and cannot be used as identifiers. For examplefn(function),struct(struct),if(conditional statement), etc.

  5. Naming Conventions: Zig officially recommends the following conventions:

    • camelCase: Used for variable names and function names. For examplemyVariable、calculateSum。
    • PascalCase: Used for type names and namespaces. For examplePoint、ArrayList。
    • SCREAMING_SNAKE_CASE: Used for constants known at compile time (comptime constants). For exampleMAX_SIZE。
  6. Optional Type: Zig has a special type?T, which represents an optional value of typeT. This is very useful when dealing with values that may be null.

  7. Compile-Time Constants: Using thecomptimekeyword before an identifier indicates that the identifier is a compile-time constant.

  8. Error Types: Using theerrorkeyword defines error types, for example:

    pub fn openFile(path: []const u8) !void {
        // ...
    }
  9. Type Suffix: Appending the_tsuffix after type names is a C language habit; in Zig you can do the same, but it is not required.

Reserved Keywords

The following are some reserved keywords in Zig:

KeywordsDescription
alignSpecifies the alignment byte count for a variable or type
allowzeroAllows pointers to point to null
andLogical AND operation
asmInline assembly block
breakBreak out of the nearest loop or scope
callconvCalling convention
constDefines a constant
continueContinue to the next loop iteration
deferDefer execution of a statement until the scope exits
elseThe negative branch of a conditional statement
enumEnum type
errdeferDeferred execution statement when an error occurs
errorError type definition
exportExport symbols for use by C language, etc.
fnFunction definition
forTraversal loop
ifConditional statement
inlineInline function or inline loop
linksectionSpecifies the linker section
noaliasPointer cannot be aliased by other pointers
noinlinePrevent function inlining
nullNull value for optional types
orLogical OR operation
packedRemoves struct padding, tightly packed by bit
pubPublic access level
returnReturn from a function
structStruct type definition
switchMulti-branch selection statement
testTest code block
threadlocalThread-local variable
tryTry to execute an expression, propagating errors upward on failure
unionUnion type definition
usingnamespaceBring all public members of a namespace into the current scope
varDefine a mutable variable
voidNo type, often used when a function has no return value
whileLoop statement

Basic Syntax

1. Variables and Constants

In Zig, variables use thevarkeyword to define, constants use theconstkeyword to define.

const x: i32 = 10;  // 定义一个整数常量 x,值为 10
var y: f64 = 3.14;  // 定义一个浮点数变量 y,值为 3.14

2. Functions

Functions use thefnkeyword to define, and specify a return type.

const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn main() !void {
    const result = add(3, 4);
    const stdout = std.io.getStdOut().writer();
    try stdout.print("Result: {}\n", .{result});
}

3. Conditional Statements

Useifandelseto implement conditional logic.

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    const number = 10;
    if (number > 0) {
        try stdout.print("Number is positive\n", .{});
    } else {
        try stdout.print("Number is not positive\n", .{});
    }
}

4. Loops

Zig supportswhileandforloops.

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // while 循环,: (i += 1) 是每次迭代后执行的更新表达式
    var i: i32 = 0;
    while (i < 5) : (i += 1) {
        try stdout.print("i: {}\n", .{i});
    }

    // for 循环,遍历数组
    const array = [5]i32{ 1, 2, 3, 4, 5 };
    for (array) |item| {
        try stdout.print("item: {}\n", .{item});
    }
}

5. Structs

Zig usesstructto define structs.

const std = @import("std");

const Point = struct {
    x: i32,
    y: i32,
};

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    const p = Point{ .x = 10, .y = 20 };
    try stdout.print("Point: ({}, {})\n", .{ p.x, p.y });
}

6. Error Handling

Zig uses error enum types and thetry / catchkeyword for error handling.

const std = @import("std");

const FileError = error{
    FileNotFound,
};

fn readFile(path: []const u8) !void {
    // 模拟一个可能失败的操作
    if (std.mem.eql(u8, path, "invalid")) {
        return FileError.FileNotFound;
    }
    // 其他操作...
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    readFile("invalid") catch |err| {
        switch (err) {
            FileError.FileNotFound => {
                try stdout.print("Error: File not found\n", .{});
            },
            else => return err,
        }
        return;
    };

    try stdout.print("File read successfully\n", .{});
}

Code analysis:

  • catch |err|: Catch the error and bind it to a variableerr。
  • switch (err): Match the error type and handle different error cases separately.
  • else => return err: Propagate unexpected errors directly upward without silently ignoring them.
  • IfreadFileexecutes successfully (without triggering catch), then continue executing the subsequent print statement.
Other Extensions