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, // 切片的长度(存储在栈上)
};
所以当你有一个切片变量时:
ptr 和 len)存储在栈上ptr 指向的内容)可以存储在各种位置const str = "hello"; // 数据在只读段,切片在栈上
var arr = [5]u8{ 'h', 'e', 'l', 'l', 'o' };
const slice = arr[0..]; // 数据在栈上,切片在栈上
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});
// 可以看到切片变量和数据指针的地址相差很大
// 说明它们确实在不同的内存区域
}
理解切片本身和数据存储位置的区别很重要,因为:
生命周期管理:
fn dangerousExample() []const u8 {
var local_array = [_]u8{ 't', 'e', 'm', 'p' };
return local_array[0..]; // 错误!返回指向栈数据的切片
} // local_array 被销毁,但返回的切片还指向它