Zig

Zig是一种通用,采用静态类型。旨在成为C语言的继任者、提供更轻量更简单的编程体验、提供更丰富的功能,以MIT许可证发布。

Zig和C语言的区别主要在控制流、函数调用、库导入、变量声明和Unicode支持,且Zig不支持宏和预处理指令。Zig从现代语言引入了编译期泛型编程特性,允许函数在编译期处理各种数据,同时添加了一些新的编译器指令,以便通过反射访问和修改类型信息。

像C语言一样,Zig没有实现垃圾回收,而是选择手动管理内存,并添加了提高代码安全性的功能,例如可选类型和单元测试框架。

Zig最初由Andrew Kelley设计,于2016年发布,开发现由Zig软件基金会资助。

描述
目标
Zig 的主要目标是成为解决目前由 C 解决的各种任务的更好的解决方案。对此的主要关注点是可读性;Zig 尽可能使用现有概念和语法,避免为相似概念添加不同的语法。此外,它的设计目标是“稳健性、最佳化和可维护性”,包括各种提高安全性、优化和测试的功能。简洁的语法是维护的重要组成部分,因为该语言的目标是允许维护人员在不需要学习他们可能不熟悉的语言细节的情况下调试代码。 即使有这些更改,Zig 也可以编译并与现有的 C 代码一起使用;可以在 Zig 项目中包含 C 头文件并调用它们的函数,并且,通过包含编译器生成的头文件,Zig 代码可以被链接到 C 项目。

为了保持整体设计理念的简洁和易读,Zig 系统整体相比于 C 及其他类似 C 的语言也包含了一些风格上的变化。例如,Rust 语言具有 运算符重载,这意味着类似 的语句实际上可能是对类型的重载版本的加运算符的函数调用。此外,该函数可能会引发 panic,从而可能中断任何后续代码。在 Zig 中,如果某个东西调用了一个函数,那么它看起来就像一个函数调用;如果没有调用,它看起来就不会像一个函数调用。如果它可能抛出错误,则一定会在代码中显式表示它可能抛出错误, 而错误处理可以通过错误类型处理,也可以通过 catch 或 try 处理。

Zig 的目标与同时期设计的许多其他语言(如 Go、Rust、Carbon 和 Nim)的目标形成对比。通常,这些语言更复杂,他们添加了运算符重载、看起来像值(属性)调用的函数等许多功能,这些旨在帮助构建大型程序。并且这些特性更接近于 C++ 的特性,而这些语言也更像 C++。 Zig 在类型系统的扩展上更为保守,支持编译时泛型,并通过 特性实现了一种 鸭子类型 形式的用法。

内存处理
C 程序中错误的主要来源之一是基于malloc的内存管理系统。malloc 会为代码使用分配一块内存,并返回该内存的引用作为一个 指针,但C没有一套系统来确保在程序不再需要内存时释放该内存,这可能导致内存泄漏以至于耗费完所有的可用内存。更常见的是悬空指针,这些指针引用未正确分配的内存地址。

Zig 旨在提供与 C 相似或更好的性能,因此 GC 和 ARC 不是合适的解决方案。相反,它使用一种现代的(截至 2022 年),被称为可选类型的概念。与指针可以指向空值或 nil 不同,这种方案使用一个单独的类型来指示可能为空的数据。这类似于使用一个指针和一个布尔值的结构来指示指针是否有效,但布尔值的状态由语言隐式管理,不需要程序员显式管理。因此,例如,当声明指针时,它被设置为“未分配”,而当该指针从 malloc 接收一个值时,如果 malloc 成功,它将被设置为“已分配”。

这种模型的优点是它具有非常低甚至是零的开销;尽管这使得编译器必须创建在操作指针时传递可选类型,而不是一个简单的指针的代码,但这允许它在编译时直接检查出可能的内存问题,而无需延后到运行时检查。例如,在 C 中创建一个具有空值的指针并尝试使用它是完全可以接受的,尽管这会导致空指针错误。相比之下,使用可选类型的语言可以保证所有代码只会在指针有效时尝试使用相应的指针。虽然这不能消除所有潜在问题,但当在运行时发生问题时,错误可以被更精确地定位和解释。

Zig 中内存管理的另一变化是:实际分配操作是通过 描述相应的操作来处理的,而不是直接调用 libc 中的内存管理函数。例如,在 C 中,如果想写一个包含多个副本的字符串的函数,该函数可能如下所示:

const char repeat(const char original, size_t times);

在代码中,该函数会检查 的大小,然后 malloc 的内存来为它将构建的字符串预留空间。但这个 malloc 对调用它的函数是不可见的,所以,如果像 repeat 这样的函数没有正常释放内存,就会发生内存泄漏。而在 Zig 中,这种操作可能通过如下函数处理:

fn repeat(allocator: *std.mem.Allocator, original: []const u8, times: usize) std.mem.Allocator.Error![]const u8;

在此代码中, 变量传递了一个内存分配器,并且 函数则返回结果字符串或 Allocator.Error。通过直接将分配器作为输入传参,使得内存分配不会被“隐藏”起来,即调用链上的所有内存分配都会通过这个分配接口进行分配。顺带一提,Zig 的标准库内没有进行任何隐式内存分配。此外,由于结构可以指向任何东西,可以使用替代分配器,甚至是程序中编写的分配器。这使不使用通常分配整个内存页的操作系统函数的小对象分配器等操作成为了可能。

可选类型是一个提供通用功能但仍然简单和通用的语言特性。它不仅可以用于解决空指针问题,还可以明确地描述“无值”场景。考虑一个名为 的函数,它返回一个整数,以及一个整数变量,,它保存结果。在许多语言中,会在 中放置一个 魔术数字 以表示 尚未被调用,而许多实现则会将其设置为零。在 Zig 中,这可以实现为 ,将变量设置为明确的“未被调用”的值。

Zig 内存管理避免了隐式分配。即分配不直接由语言本身进行管理。相反,用户需要通过 标准库 明确地进行堆访问来进行显式内存管理。

与 C 的直接交互
Zig 提倡一种将新 Zig 代码与现有 C 代码结合的渐进方法。为此,它可以尽可能无缝地与现有 C 库进行交互。Zig 使用 指令导入库,通常如下所示:

const std = @import("std");

如此便可以调用 std 内的函数,例如:

std.debug.print("Hello, world!\n", .{});

要加载 C 代码,只需将 替换为 :

const c = @cImport(@cInclude("soundio/soundio.h"));

然后我们就可以像调用本地 Zig 代码一样调用 soundio 库中的函数。由于 Zig 使用新数据类型,它们是显式定义的,不像 C 的更通用的 和 ,我们需要使用少量指令在 C 和 Zig 类型之间移动数据,包括 和 。

在编译时,类型成为 一级公民。这使得在编译时 鸭子类型 成为可能,这也是 Zig 实现泛型类型的方式。

其他特性
Zig 支持 编译时 泛型编程、反射编程 和评估、交叉编译 以及 手动内存管理。 该语言的一个主要目标是改进 C 语言, 同时也从 Rust 等语言中汲取灵感, 等等。Zig 具有许多用于 低级编程语言 的特性,特别是紧凑结构(没有字段之间的填充的结构)、任意宽度的整数 和多种指针类型。

Zig 不仅仅是一种新语言:它还包括一个 C/C++ 编译器,可以与这两种语言一起使用。

缺点
Zig 有一些缺点。如果内存没有正确释放,由于缺乏隐式控制,可能会因为忘记 defer 等必要的手动操作导致内存泄漏。 对于那些不熟悉低级编程概念的人来说,学习 Zig 的曲线可能很陡峭。 并且 LLVM 是用 C++ 编写的。带有 LLVM 的 Zig 编译器是 169 MiB,而不带 LLVM 的则是 4.4 MiB。通常情况下,使用新的基于 Zig 语言的编译器编译的可执行代码更快,其 LLVM 代码生成更好,并修复了许多错误,但在 0.10 版本中也对旧的遗留编译器进行了改进。自托管链接器与自托管编译器紧密耦合。新版本还增加了一些对 AMD GPU 的实验性(第 3 层)支持(源代码中还有对 Nvidia GPU 和 PlayStation 4 和 5 的一些较少支持)。

旧的 自举 ("stage1") 编译器是用 Zig 和 C++ 编写的,使用 LLVM 13 作为后端, 支持其许多本机目标。 编译器也是 自由及开放源代码软件,在 MIT 许可证 下发布。 Zig 编译器提供了类似于 Clang 的编译 C 和 C++ 的能力,命令为 zig cc 和 zig c++, 提供了包括 C 标准库 (libc) 和 C++ 标准库 (libcxx) 在内的许多不同平台的头文件,允许 Zig 的 cc 和 c++ 子命令作为开箱即用的 交叉编译器。

此外,官方支持(并记录)的操作系统(主要是桌面操作系统)上可以制作(最小)应用程序,这些应用程序也可以为 Android(使用 Android NDK)和 iOS 编程。

包管理
在0.11.0版本之前,Zig没有内置的包管理器,但在0.11.0版本中包含了一个实验性的包管理器,并在0.12.0中进一步扩展。

Zig没有官方的包仓库;相反,包只是一个指向归档文件或Git仓库的URL。理想情况下,当解压缩时,包括一个标准的build.zig文件(Zig 编译器按惯例使用该文件来编译源代码)和一个build.zig.zon文件,用于定义包的名称和版本。

Zig 的开发由 Zig 软件基金会(ZSF)资助,ZSF 是一个由 Andrew Kelley 担任总裁的非营利公司,接受捐赠并雇佣多名全职员工。

示例
Hello World
泛型链表
const std = @import("std");
const stdout = std.io.getStdOut().writer();

fn LinkedList(comptime T: type) type {
return struct {
const Self = @This();
pub const Node = struct {
next: ?*Node = null,
data: T,
};

first: ?*Node = null,

pub fn prepend(
list: *Self,
new_node: *Node,
) void {
new_node.next = list.first;
list.first = new_node;
}
pub fn format(
list: Self,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
out_stream: anytype,
) !void {
try out_stream.writeAll("( ");
var it = list.first;
while (it) |node| : (it = node.next) {
try std.fmt.formatType(
node.data,
fmt,
options,
out_stream,
1,
);
try out_stream.writeAll(" ");
}
try out_stream.writeAll(")");
}
};
}

pub fn main() !void {
const ListU32 = LinkedList(u32);
var list = ListU32{};
var node1 = ListU32.Node{ .data = 1 };
var node2 = ListU32.Node{ .data = 2 };
var node3 = ListU32.Node{ .data = 3 };
list.prepend(&node1);
list.prepend(&node2);
list.prepend(&node3);
try stdout.print("{}\n", .{list});
try stdout.print("{b}\n", .{list});
}

  • 输出

*:
( 3 2 1 )
( 11 10 1 )

带分配器的字符串重复
const std = @import("std");

fn repeat(
allocator: *std.mem.Allocator,
original: []const u8,
times: usize,
) std.mem.Allocator.Error![]const u8 {
var buffer = try allocator.alloc(
u8,
original.len * times,
);

for (0..times) |i| {
std.mem.copyForwards(
u8,
buffer[(original.len * i)..],
original,
);
}

return buffer;
}

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

var arena = std.heap.ArenaAllocator.init(
std.heap.page_allocator,
);
defer arena.deinit();

var allocator = arena.allocator();

const original = "Hello ";
const repeated = try repeat(
&allocator,
original,
3,
);

// 输出 "Hello Hello Hello "
try stdout.print("{s}\n", .{repeated});
}

  • 输出

*:
Hello Hello Hello

社区
Zig 软件基金会(ZSF)有一个非常活跃的贡献者社区,并且仍处于早期发展阶段。 尽管如此,2024 年的一项 Stack Overflow 调查发现,Zig 软件开发人员的平均年薪为 103,000 美元,使其成为薪资最高的编程语言之一。 然而,只有 0.83% 的受访者表示他们精通 Zig。 是一个用 Zig 编写的 终端模拟器。

  • TigerBeetle 是一个用 Zig 编写的金融交易数据库。

参见
*C
*C++
*D
*Nim
*Go
*Rust
*Carbon
*V

参考文献
引用
书目
*
*
*
*

外部链接
*
*
*[https://www.youtube.com/watch?v=Z4oYSByyRak 视频:介绍 Zig]
*[https://www.youtube.com/watch?v=Gv2I7qTux7g 视频:The Road to 1.0]
*[https://discu.eu/weekly/zig/ Zig Weekly]
*[https://ziglang.cc/ 中文社区]

评论 (0)

  • 还没有评论,来抢沙发吧。