Skip to content

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 的类型系统既强大又灵活,为编写安全高效的代码提供了坚实基础。在下一章中,我们将学习如何使用这些类型来声明和操作变量与常量。

本站内容仅供学习和研究使用。