Zig 数据类型
Zig 拥有丰富而精确的类型系统,本章将详细介绍 Zig 中的各种数据类型。
整数类型
有符号整数
Zig 提供了多种大小的有符号整数类型:
zig
const std = @import("std");
pub fn main() void {
const i8_val: i8 = -128; // 8位有符号整数 (-128 到 127)
const i16_val: i16 = -32768; // 16位有符号整数
const i32_val: i32 = -2147483648; // 32位有符号整数
const i64_val: i64 = -9223372036854775808; // 64位有符号整数
std.debug.print("i8: {}, i16: {}, i32: {}, i64: {}\n",
.{ i8_val, i16_val, i32_val, i64_val });
}无符号整数
zig
const std = @import("std");
pub fn main() void {
const u8_val: u8 = 255; // 8位无符号整数 (0 到 255)
const u16_val: u16 = 65535; // 16位无符号整数
const u32_val: u32 = 4294967295; // 32位无符号整数
const u64_val: u64 = 18446744073709551615; // 64位无符号整数
std.debug.print("u8: {}, u16: {}, u32: {}, u64: {}\n",
.{ u8_val, u16_val, u32_val, u64_val });
}任意位宽整数
Zig 支持任意位宽的整数类型:
zig
const std = @import("std");
pub fn main() void {
const i3_val: i3 = -4; // 3位有符号整数 (-4 到 3)
const u3_val: u3 = 7; // 3位无符号整数 (0 到 7)
const i12_val: i12 = -2048; // 12位有符号整数
const u24_val: u24 = 16777215; // 24位无符号整数
std.debug.print("i3: {}, u3: {}, i12: {}, u24: {}\n",
.{ i3_val, u3_val, i12_val, u24_val });
}特殊整数类型
zig
const std = @import("std");
pub fn main() void {
// isize 和 usize:与指针大小相同的整数
const isize_val: isize = -1000;
const usize_val: usize = 1000;
// c_int, c_uint:与 C 语言兼容的整数类型
const c_int_val: c_int = 42;
const c_uint_val: c_uint = 42;
std.debug.print("isize: {}, usize: {}\n", .{ isize_val, usize_val });
std.debug.print("c_int: {}, c_uint: {}\n", .{ c_int_val, c_uint_val });
}浮点数类型
标准浮点数
zig
const std = @import("std");
pub fn main() void {
const f16_val: f16 = 3.14; // 16位浮点数(半精度)
const f32_val: f32 = 3.14159; // 32位浮点数(单精度)
const f64_val: f64 = 3.141592653589793; // 64位浮点数(双精度)
const f128_val: f128 = 3.1415926535897932384626433832795; // 128位浮点数
std.debug.print("f16: {d:.2}\n", .{f16_val});
std.debug.print("f32: {d:.5}\n", .{f32_val});
std.debug.print("f64: {d:.15}\n", .{f64_val});
std.debug.print("f128: {d:.30}\n", .{f128_val});
}C 兼容浮点数
zig
const std = @import("std");
pub fn main() void {
const c_longdouble_val: c_longdouble = 3.14159;
std.debug.print("c_longdouble: {d:.5}\n", .{c_longdouble_val});
}布尔类型
zig
const std = @import("std");
pub fn main() void {
const is_true: bool = true;
const is_false: bool = false;
// 布尔运算
const and_result = is_true and is_false; // false
const or_result = is_true or is_false; // true
const not_result = !is_true; // false
std.debug.print("true: {}, false: {}\n", .{ is_true, is_false });
std.debug.print("and: {}, or: {}, not: {}\n", .{ and_result, or_result, not_result });
}字符和字符串类型
字符类型
在 Zig 中,字符实际上是整数:
zig
const std = @import("std");
pub fn main() void {
const char_a: u8 = 'A'; // ASCII 字符
const char_unicode: u21 = '中'; // Unicode 字符
std.debug.print("ASCII 字符 'A': {} (值: {})\n", .{ char_a, char_a });
std.debug.print("Unicode 字符 '中': {u} (值: {})\n", .{ char_unicode, char_unicode });
}字符串类型
zig
const std = @import("std");
pub fn main() void {
// 字符串字面量的类型是 *const [N:0]u8
const string_literal = "Hello, 世界!";
// 字符串切片
const string_slice: []const u8 = "Hello, Zig!";
// 可变字符串(字符数组)
var mutable_string = [_]u8{'H', 'e', 'l', 'l', 'o'};
std.debug.print("字符串字面量: {s}\n", .{string_literal});
std.debug.print("字符串切片: {s}\n", .{string_slice});
std.debug.print("可变字符串: {s}\n", .{mutable_string});
// 修改可变字符串
mutable_string[0] = 'h';
std.debug.print("修改后: {s}\n", .{mutable_string});
}数组类型
固定大小数组
zig
const std = @import("std");
pub fn main() void {
// 显式大小数组
const numbers: [5]i32 = [5]i32{ 1, 2, 3, 4, 5 };
// 推断大小数组
const fruits = [_][]const u8{ "苹果", "香蕉", "橙子" };
// 重复初始化
const zeros = [_]i32{0} ** 10; // 10个0
std.debug.print("数字数组长度: {}\n", .{numbers.len});
std.debug.print("水果数组: ");
for (fruits) |fruit| {
std.debug.print("{s} ", .{fruit});
}
std.debug.print("\n");
std.debug.print("前5个零: ");
for (zeros[0..5]) |zero| {
std.debug.print("{} ", .{zero});
}
std.debug.print("\n");
}多维数组
zig
const std = @import("std");
pub fn main() void {
// 二维数组
const matrix: [3][3]i32 = [3][3]i32{
[3]i32{ 1, 2, 3 },
[3]i32{ 4, 5, 6 },
[3]i32{ 7, 8, 9 },
};
std.debug.print("3x3 矩阵:\n");
for (matrix) |row| {
for (row) |val| {
std.debug.print("{} ", .{val});
}
std.debug.print("\n");
}
}切片类型
zig
const std = @import("std");
pub fn main() void {
var array = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 切片是对数组部分的引用
const slice1: []i32 = array[2..7]; // 索引 2 到 6
const slice2: []i32 = array[0..]; // 从开始到结束
const slice3: []const i32 = array[5..8]; // 只读切片
std.debug.print("原数组: ");
for (array) |val| {
std.debug.print("{} ", .{val});
}
std.debug.print("\n");
std.debug.print("切片1 [2..7]: ");
for (slice1) |val| {
std.debug.print("{} ", .{val});
}
std.debug.print("\n");
std.debug.print("切片2 [0..]: ");
for (slice2) |val| {
std.debug.print("{} ", .{val});
}
std.debug.print("\n");
// 修改切片会影响原数组
slice1[0] = 100;
std.debug.print("修改后的数组: ");
for (array) |val| {
std.debug.print("{} ", .{val});
}
std.debug.print("\n");
}指针类型
单项指针
zig
const std = @import("std");
pub fn main() void {
var number: i32 = 42;
// 单项指针
const ptr: *i32 = &number;
const const_ptr: *const i32 = &number;
std.debug.print("原值: {}\n", .{number});
std.debug.print("通过指针访问: {}\n", .{ptr.*});
// 通过指针修改值
ptr.* = 100;
std.debug.print("修改后: {}\n", .{number});
}多项指针
zig
const std = @import("std");
pub fn main() void {
var array = [_]i32{ 1, 2, 3, 4, 5 };
// 多项指针
const multi_ptr: [*]i32 = &array;
std.debug.print("通过多项指针访问:\n");
var i: usize = 0;
while (i < array.len) : (i += 1) {
std.debug.print("array[{}] = {}\n", .{ i, multi_ptr[i] });
}
}C 指针
zig
const std = @import("std");
pub fn main() void {
var number: i32 = 42;
// C 指针(可以为 null)
var c_ptr: ?*i32 = &number;
var null_ptr: ?*i32 = null;
if (c_ptr) |ptr| {
std.debug.print("C 指针值: {}\n", .{ptr.*});
}
if (null_ptr) |ptr| {
std.debug.print("不会执行\n", .{});
} else {
std.debug.print("null_ptr 是 null\n", .{});
}
}可选类型
zig
const std = @import("std");
pub fn main() void {
// 可选类型可以是值或 null
var maybe_number: ?i32 = 42;
var maybe_null: ?i32 = null;
// 使用 if 解包可选值
if (maybe_number) |num| {
std.debug.print("数字是: {}\n", .{num});
} else {
std.debug.print("没有数字\n", .{});
}
if (maybe_null) |num| {
std.debug.print("不会执行\n", .{});
} else {
std.debug.print("maybe_null 是 null\n", .{});
}
// 使用 orelse 提供默认值
const number = maybe_null orelse 0;
std.debug.print("使用默认值: {}\n", .{number});
}错误联合类型
zig
const std = @import("std");
// 定义错误集合
const MathError = error{
DivisionByZero,
Overflow,
};
fn divide(a: i32, b: i32) MathError!i32 {
if (b == 0) return MathError.DivisionByZero;
return @divTrunc(a, b);
}
pub fn main() void {
// 错误联合类型
const result1 = divide(10, 2);
const result2 = divide(10, 0);
// 处理成功情况
if (result1) |value| {
std.debug.print("10 / 2 = {}\n", .{value});
} else |err| {
std.debug.print("错误: {}\n", .{err});
}
// 处理错误情况
if (result2) |value| {
std.debug.print("10 / 0 = {}\n", .{value});
} else |err| {
std.debug.print("错误: {}\n", .{err});
}
// 使用 catch 提供默认值
const safe_result = divide(10, 0) catch 0;
std.debug.print("安全除法结果: {}\n", .{safe_result});
}结构体类型
zig
const std = @import("std");
const Point = struct {
x: f32,
y: f32,
// 结构体方法
pub fn distance(self: Point, other: Point) f32 {
const dx = self.x - other.x;
const dy = self.y - other.y;
return @sqrt(dx * dx + dy * dy);
}
};
pub fn main() void {
const p1 = Point{ .x = 0.0, .y = 0.0 };
const p2 = Point{ .x = 3.0, .y = 4.0 };
std.debug.print("点1: ({d:.1}, {d:.1})\n", .{ p1.x, p1.y });
std.debug.print("点2: ({d:.1}, {d:.1})\n", .{ p2.x, p2.y });
std.debug.print("距离: {d:.2}\n", .{p1.distance(p2)});
}枚举类型
简单枚举
zig
const std = @import("std");
const Color = enum {
Red,
Green,
Blue,
};
pub fn main() void {
const my_color = Color.Red;
switch (my_color) {
Color.Red => std.debug.print("颜色是红色\n", .{}),
Color.Green => std.debug.print("颜色是绿色\n", .{}),
Color.Blue => std.debug.print("颜色是蓝色\n", .{}),
}
}带值的枚举
zig
const std = @import("std");
const Status = enum(u8) {
Ok = 0,
Error = 1,
Pending = 2,
pub fn toString(self: Status) []const u8 {
return switch (self) {
.Ok => "成功",
.Error => "错误",
.Pending => "等待中",
};
}
};
pub fn main() void {
const status = Status.Ok;
std.debug.print("状态: {} ({})\n", .{ status, status.toString() });
std.debug.print("状态值: {}\n", .{@intFromEnum(status)});
}联合类型
标记联合
zig
const std = @import("std");
const Value = union(enum) {
Integer: i32,
Float: f64,
String: []const u8,
Boolean: bool,
};
pub fn main() void {
const values = [_]Value{
Value{ .Integer = 42 },
Value{ .Float = 3.14 },
Value{ .String = "Hello" },
Value{ .Boolean = true },
};
for (values) |value| {
switch (value) {
.Integer => |int| std.debug.print("整数: {}\n", .{int}),
.Float => |float| std.debug.print("浮点数: {d:.2}\n", .{float}),
.String => |string| std.debug.print("字符串: {s}\n", .{string}),
.Boolean => |boolean| std.debug.print("布尔值: {}\n", .{boolean}),
}
}
}函数类型
zig
const std = @import("std");
// 函数类型定义
const BinaryOp = fn (i32, i32) i32;
fn add(a: i32, b: i32) i32 {
return a + b;
}
fn multiply(a: i32, b: i32) i32 {
return a * b;
}
fn calculate(op: BinaryOp, a: i32, b: i32) i32 {
return op(a, b);
}
pub fn main() void {
const result1 = calculate(add, 5, 3);
const result2 = calculate(multiply, 5, 3);
std.debug.print("5 + 3 = {}\n", .{result1});
std.debug.print("5 * 3 = {}\n", .{result2});
}类型转换
显式类型转换
zig
const std = @import("std");
pub fn main() void {
const int_val: i32 = 42;
const float_val: f64 = 3.14;
// 整数转换
const u32_val: u32 = @intCast(int_val);
const i64_val: i64 = @intCast(int_val);
// 浮点数转换
const f32_val: f32 = @floatCast(float_val);
const int_from_float: i32 = @intFromFloat(float_val);
const float_from_int: f64 = @floatFromInt(int_val);
std.debug.print("原整数: {}\n", .{int_val});
std.debug.print("转为 u32: {}\n", .{u32_val});
std.debug.print("转为 i64: {}\n", .{i64_val});
std.debug.print("原浮点数: {d:.2}\n", .{float_val});
std.debug.print("转为 f32: {d:.2}\n", .{f32_val});
std.debug.print("转为整数: {}\n", .{int_from_float});
std.debug.print("整数转浮点: {d:.2}\n", .{float_from_int});
}位转换
zig
const std = @import("std");
pub fn main() void {
const float_val: f32 = 3.14;
const int_bits: u32 = @bitCast(float_val);
const back_to_float: f32 = @bitCast(int_bits);
std.debug.print("浮点数: {d:.2}\n", .{float_val});
std.debug.print("位表示: 0x{X}\n", .{int_bits});
std.debug.print("转回浮点: {d:.2}\n", .{back_to_float});
}编译时类型
comptime_int 和 comptime_float
zig
const std = @import("std");
pub fn main() void {
// 编译时整数可以是任意大小
const big_number = 123456789012345678901234567890;
// 编译时浮点数有无限精度
const precise_pi = 3.1415926535897932384626433832795028841971693993751;
// 运行时需要指定具体类型
const runtime_int: i64 = big_number % 1000000;
const runtime_float: f64 = precise_pi;
std.debug.print("大整数的后6位: {}\n", .{runtime_int});
std.debug.print("π (f64精度): {d:.15}\n", .{runtime_float});
}类型信息和反射
zig
const std = @import("std");
const Person = struct {
name: []const u8,
age: u32,
};
pub fn main() void {
// 获取类型信息
const person_type = @TypeOf(Person{});
const int_type = @TypeOf(@as(i32, 0));
std.debug.print("Person 类型: {}\n", .{person_type});
std.debug.print("i32 类型: {}\n", .{int_type});
// 类型大小
std.debug.print("Person 大小: {} 字节\n", .{@sizeOf(Person)});
std.debug.print("i32 大小: {} 字节\n", .{@sizeOf(i32)});
// 类型对齐
std.debug.print("Person 对齐: {} 字节\n", .{@alignOf(Person)});
std.debug.print("i32 对齐: {} 字节\n", .{@alignOf(i32)});
}总结
本章详细介绍了 Zig 的类型系统:
- ✅ 整数类型:有符号、无符号、任意位宽
- ✅ 浮点数类型:不同精度的浮点数
- ✅ 布尔类型和字符串类型
- ✅ 数组、切片和指针类型
- ✅ 可选类型和错误联合类型
- ✅ 结构体、枚举和联合类型
- ✅ 函数类型和类型转换
- ✅ 编译时类型和类型反射
Zig 的类型系统既强大又灵活,为编写安全高效的代码提供了坚实基础。在下一章中,我们将学习如何使用这些类型来声明和操作变量与常量。