0%

Zig初见

什么是Zig?

Zig is a general-purpose programming language and toolchain for maintaining robust, optimal and reusable software.

按照官网所说, Zig是一种通用编程语言和工具链, 用于维护健壮、最佳和可重用的软件.

特点

  • 无GC, 手动管理内存(支持arena等多种Allocator)
  • 强大的编译时计算能力
  • 类型可以在编译时像变量一样传递
  • 超多Targets交叉编译
  • 直接调用C语言代码和库

Hello, World

1
2
3
4
5
6
const std = @import("std");

pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, {s}!\n", .{"world"});
}
  • 通过 @import() 导入文件, 以 @ 开头的函数为编译器内置函数
  • !voidvoidanyerror 的和类型

编译时计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
fn LinkedList(comptime T: type) type {
return struct {
pub const Node = struct {
prev: ?*Node,
next: ?*Node,
data: T,
};

first: ?*Node,
last: ?*Node,
len: usize,
};
}

test "linked list" {
// Functions called at compile-time are memoized. This means you can
// do this:
try expect(LinkedList(i32) == LinkedList(i32));

var list = LinkedList(i32) {
.first = null,
.last = null,
.len = 0,
};
try expect(list.len == 0);

// Since types are first class values you can instantiate the type
// by assigning it to a variable:
const ListOfInts = LinkedList(i32);
try expect(ListOfInts == LinkedList(i32));
}

调用C语言

可以通过 zig translate-c 翻译C源文件为Zig源码, 甚至可以在Zig代码中通过 @cImport 直接导入C源文件和代码, 两者原理相同.

以调用OpenSSL计算MD5为例(Zig标准库支持MD5计算: std.crypto.hash.Md5, 此处仅为演示):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const std = @import("std");
const debug = std.debug;

const ssl = @cImport({
@cInclude("openssl/ssl.h");
@cInclude("openssl/crypto.h");
@cInclude("openssl/md5.h");
}); // 导入OpenSSL头文件

fn md5sum(bytes: anytype) [ssl.MD5_DIGEST_LENGTH]u8 {
comptime debug.assert(@TypeOf(bytes[0]) == u8);
var md: [ssl.MD5_DIGEST_LENGTH]u8 = undefined;
_ = ssl.MD5(bytes, bytes.len, &md); // 调用C函数
return md;
}

build.zig 中添加链接库:

1
2
exe.linkSystemLibrary("libcrypto");  // 确保pkgconfig可以找到OpenSSL库, 此处就可以自动处理Include路径及链接库路径
exe.linkSystemLibrary("libssl");

内建Test

如同Go和Rust, Zig也内建test支持

1
2
3
test "simple test" {
try std.testing.expectEqual(2, 1 + 1);
}

run:

zig test name.zig or zig build test

内存管理

arena示例

1
2
3
4
5
6
7
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var map = std.StringHashMap([]const u8).init(allocator);
defer map.deinit();
try map.put("key", "value");
try testing.expect(std.mem.eql(u8, "value", map.get("key") orelse ""));

可空类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var foo: ?i32 = null;

// Coerce from child type of an optional
foo = 1234;

// Use compile-time reflection to access the child type of the optional:
comptime try expect(@typeInfo(@TypeOf(foo)).Optional.child == i32);

// Pointers cannot be null. If you want a null pointer, use the optional
// prefix `?` to make the pointer type optional.
var ptr: ?*i32 = null;

var x: i32 = 1;
ptr = &x;

try expect(ptr.?.* == 1);

// Optional pointers are the same size as normal pointers, because pointer
// value 0 is used as the null value.
try expect(@sizeOf(?*i32) == @sizeOf(*i32));

错误处理

1
2
3
4
5
6
7
8
9
10
fn failingFunction() error{Oops}!void {
return error.Oops;
}

test "returning an error" {
failingFunction() catch |err| {
try expect(err == error.Oops);
return;
};
}

交叉编译

1
$ zig targets

构建系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ zig help
Usage: zig [command] [options]

Commands:

build Build project from build.zig
init-exe Initialize a `zig build` application in the cwd
init-lib Initialize a `zig build` library in the cwd

ast-check Look for simple compile errors in any set of files
build-exe Create executable from source or object files
build-lib Create library from source or object files
build-obj Create object from source or object files
fmt Reformat Zig source into canonical form
run Create executable and run immediately
test Create and run a test build
translate-c Convert C code to Zig code

ar Use Zig as a drop-in archiver
cc Use Zig as a drop-in C compiler
c++ Use Zig as a drop-in C++ compiler
dlltool Use Zig as a drop-in dlltool.exe
lib Use Zig as a drop-in lib.exe
ranlib Use Zig as a drop-in ranlib
objcopy Use Zig as a drop-in objcopy

env Print lib path, std path, cache directory, and version
help Print this help and exit
libc Display native libc paths file or validate one
targets List available compilation targets
version Print version number and exit
zen Print Zen of Zig and exit

General Options:

-h, --help Print command-specific usage

包管理

暂时还没有