Skip to content
zig 版本:0.13.0

字符与布尔值

计算机中的字符并非我们平常所指的单个文字。特定的编码方案首先需要将单个文字对应到若干个码位,存储码位时还需要转换为字节序列。

布尔值往往通过二进制的 0 和 1 来表示。

字符

我们通常简单地将“字符”解释为我们能够看到、操作的单个文字,例如 Z👍

但在计算机中则不同:与整数、实数的表示一样,要表示字符,就需要首先划定能够表示的字符范围,为这个范围内的字符分配唯一的数字。在 Unicode 中,这个唯一的数字被称为“码位”(Code Point)。

尽管大多数情况下,码位与字符一一对应,但实际仍然存在很多特殊情况。

比如 à 看上去是同一个字符、编辑时删起来也感觉是单个字符,但其实前者只占一个码位(U+00E0),而后者则是普通拉丁字母 a(U+0061)与组合用重音符 ◌̀(U+0300)的序列,占两个码位。日常生活中常见的 emoji 也有很多需要多个码位才能够表示。

因此,现代编程语言中常常会避免可能存在歧义的“字符”,转而使用“码位”或特定编码的“编码单元”作为最基础的单位来描述字符串相关的概念。

Unicode 码位字面量

zig 中并没有专门的字符类型,与之最接近的是 Unicode 码位字面量。

使用单引号将文字包围,就是 Unicode 码位字面量。这是一种 comptime_int 类型的值,表示的是单个 Unicode 码位。

zig
// 格式化时,可以使用 u 输出对应的字符
const me_zh = '我';
print("{0u} = {0x}\n", .{me_zh}); // 我 = 6211

// 如果是 ASCII 字符,还可以使用 c 进行格式化
const me_en = 'I';
print("{0u} = {0c} = {0x}\n", .{me_en}); // I = I = 49

// 下面的写法会报错,因为这些 emoji 虽然看上去只有一个字,但其实需要由多个码位组合而成
// const hand = '🖐🏽';
// const flag = '🇨🇳';

字符串字面量

zig 中的字符串字面量是一个单项指针,指向的是将字符串进行 UTF-8 编码后得到的字节数组。这个数组和 C 语言中的字符串一样,都是以 NUL 字符结尾的。因此,字符串字面量既可以隐式转换为 u8 切片,也可以隐式转换为以 0 结尾的指针。

zig
// 存储的是 UTF-8 编码序列
const bytes = "Hello, 世界!";

print("{}\n", .{@TypeOf(bytes)}); // *const [16:0]u8
print("{}\n", .{bytes.len}); // 16

// 通过索引访问到的是 UTF-8 编码序列中的字节
// 由于 UTF-8 兼容 ASCII,所以可以直接打印 ASCII 字符
print("{c}\n", .{bytes[1]}); // 'e'

// “世”字的 UTF-8 编码为 E4 B8 96
try expect(bytes[7] == 0xE4);
try expect(bytes[8] == 0xB8);
try expect(bytes[9] == 0x96);

// 以 NUL 结尾
print("{d}\n", .{bytes[16]}); // 0

与 C 语言不同的是,zig 中的字符串字面量与 Unicode 码位字面量并没有任何的关系。对字符串字面量求索引得到的是编码序列中的某个字节,并不是 Unicode 码位。但由于 UTF-8 编码兼容 ASCII,所以对于 ASCII 字符而言,两者的数值恰巧相等。

正确处理 UTF-8 字符串是一件相当复杂的工作。标准库在 std.unicode 包中提供了用来操作 Unicode 码位和 UTF-8 编码序列的工具。

🅿️ 只能是 UTF-8 编码吗?

其实并不是。字符串字面量可以借助 \xNN 转义序列存放任意形式的数据。

但 zig 源文件使用 UTF-8 编码,并且 \u{NNNNNN} 转义序列固定生成的是码位对应的 UTF-8 编码序列,所以字符串字面量在正常情况下存放的都是 UTF-8 数据。

多行字符串字面量使用 \\ 开头,不会执行任何转义,不包含最后一行的换行。

zig
// “我”字的 UTF-8 编码为 E6 88 91
const string =
    \\I
    \\我
;
try expect(string[0] == 'I');
try expect(string[1] == '\n');
try expect(string[2] == 0xE6);
try expect(string[3] == 0x88);
try expect(string[4] == 0x91);
try expect(string[5] == 0);
try expect(string.len == 5);

C 中的字符类型

zig 还提供了 c_char 类型,对应 C 中的 char 类型。主要用于与 C 的交互,其他情况下不建议使用。

u8c_char

u8c_char 并不是全等的,因为 c_char 虽然是 8 位,但是它是否有符号取决于 target (目标机器)。

布尔值

常用于流程控制

在 zig 中,布尔值有两个,分别是 truefalse, 它们在内存中占用的大小为1个字节。