切片本身存储在栈上

const std = @import("std");

pub fn main() void {
    // 字符串字面量在只读数据段
    const literal = "hello world";

    // 切片变量 `slice` 本身存储在栈上
    const slice: []const u8 = literal;

    std.debug.print("切片地址: {*}\\n", .{&slice});      // 栈地址
    std.debug.print("数据地址: {*}\\n", .{slice.ptr});   // 只读数据段地址
    std.debug.print("切片长度: {}\\n", .{slice.len});
}

切片的结构

在 Zig 中,切片实际上是一个包含两个字段的结构:

// 切片的内存表示(概念上的)
const Slice = struct {
    ptr: [*]const T,  // 指向数据的指针(存储在栈上)
    len: usize,       // 切片的长度(存储在栈上)
};

所以当你有一个切片变量时:

数据可能存储的位置

1. 只读数据段(字符串字面量)

const str = "hello"; // 数据在只读段,切片在栈上

2. 栈上(数组的切片)

var arr = [5]u8{ 'h', 'e', 'l', 'l', 'o' };
const slice = arr[0..]; // 数据在栈上,切片在栈上

3. 堆上(动态分配)

const allocator = std.heap.page_allocator;
const heap_slice = try allocator.alloc(u8, 10); // 数据在堆上,切片在栈上
defer allocator.free(heap_slice);

验证存储位置

pub fn main() void {
    // 情况1:字符串字面量
    const literal_slice = "I'm in read-only memory";
    std.debug.print("字面量切片栈地址: {*}\\n", .{&literal_slice});
    std.debug.print("字面量数据地址: {*}\\n", .{literal_slice.ptr});

    // 情况2:栈上数组的切片
    var stack_array = [_]u8{ 'a', 'b', 'c' };
    const array_slice = stack_array[0..];
    std.debug.print("数组切片栈地址: {*}\\n", .{&array_slice});
    std.debug.print("数组数据地址: {*}\\n", .{array_slice.ptr});

    // 可以看到切片变量和数据指针的地址相差很大
    // 说明它们确实在不同的内存区域
}

为什么这个区别很重要?

理解切片本身和数据存储位置的区别很重要,因为:

  1. 生命周期管理:

    fn dangerousExample() []const u8 {
        var local_array = [_]u8{ 't', 'e', 'm', 'p' };
        return local_array[0..]; // 错误!返回指向栈数据的切片
    } // local_array 被销毁,但返回的切片还指向它