834 字
4 分钟
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#

const std = @import("std");

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

编译时计算#

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, 此处仅为演示):

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 中添加链接库:

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

内建Test#

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

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

run:

zig test name.zig or zig build test

内存管理#

arena示例

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 ""));

可空类型#

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));

错误处理#

fn failingFunction() error{Oops}!void {
    return error.Oops;
}

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

交叉编译#

$ zig targets

构建系统#

$ 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

包管理#

暂时还没有

Zig 初见
https://shsuco.com/posts/zig初见/
作者
shsuco
发布于
2023-05-07
许可协议
CC BY-NC-SA 4.0