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)
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:
-
Letters and Digits: Identifiers can contain letters (A-Z and a-z), digits (0-9), and underscores (_).
-
Starting Character: Identifiers must start with a letter or underscore, and cannot start with a digit.
-
Case Sensitivity: Zig is a case-sensitive language, which means
Variableandvariableare two different identifiers. -
Keywords and Reserved Words: Some specific words are reserved in Zig and cannot be used as identifiers. For example
fn(function),struct(struct),if(conditional statement), etc. -
Naming Conventions: Zig officially recommends the following conventions:
- camelCase: Used for variable names and function names. For example
myVariable、calculateSum。 - PascalCase: Used for type names and namespaces. For example
Point、ArrayList。 - SCREAMING_SNAKE_CASE: Used for constants known at compile time (comptime constants). For example
MAX_SIZE。
- camelCase: Used for variable names and function names. For example
-
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. -
Compile-Time Constants: Using the
comptimekeyword before an identifier indicates that the identifier is a compile-time constant. -
Error Types: Using the
errorkeyword defines error types, for example:pub fn openFile(path: []const u8) !void { // ... } -
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:
| Keywords | Description |
|---|---|
align | Specifies the alignment byte count for a variable or type |
allowzero | Allows pointers to point to null |
and | Logical AND operation |
asm | Inline assembly block |
break | Break out of the nearest loop or scope |
callconv | Calling convention |
const | Defines a constant |
continue | Continue to the next loop iteration |
defer | Defer execution of a statement until the scope exits |
else | The negative branch of a conditional statement |
enum | Enum type |
errdefer | Deferred execution statement when an error occurs |
error | Error type definition |
export | Export symbols for use by C language, etc. |
fn | Function definition |
for | Traversal loop |
if | Conditional statement |
inline | Inline function or inline loop |
linksection | Specifies the linker section |
noalias | Pointer cannot be aliased by other pointers |
noinline | Prevent function inlining |
null | Null value for optional types |
or | Logical OR operation |
packed | Removes struct padding, tightly packed by bit |
pub | Public access level |
return | Return from a function |
struct | Struct type definition |
switch | Multi-branch selection statement |
test | Test code block |
threadlocal | Thread-local variable |
try | Try to execute an expression, propagating errors upward on failure |
union | Union type definition |
usingnamespace | Bring all public members of a namespace into the current scope |
var | Define a mutable variable |
void | No type, often used when a function has no return value |
while | Loop 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.- If
readFileexecutes successfully (without triggering catch), then continue executing the subsequent print statement.