zig-json
Zig JSON 处理技能。涉及 std.json 和 std.zon 的解析、序列化、自定义序列化、流式处理。在需要处理 JSON/ZON 数据时调用。
Zig JSON 处理技能。涉及 std.json 和 std.zon 的解析、序列化、自定义序列化、流式处理。在需要处理 JSON/ZON 数据时调用。
基于 std.json 和 std.zon 的数据序列化(Zig 0.16.0)。
jsonStringify、jsonParseFromValue)zig version)zig-http 技能zig-build-system 技能本技能不收集、存储或传输任何用户数据。
步骤 1. 确定输入 — 静态类型(结构体)还是动态(Value)
步骤 2. 解析 — parseFromSlice 或 parseFromSliceLeaky
步骤 3. 使用数据 — 访问字段/遍历
步骤 4. 清理 — parsed.deinit() 释放内存
const Config = struct {
name: []const u8,
port: u16,
enabled: bool = true,
};
const json_str = \\{"name": "server", "port": 8080};
const parsed = try std.json.parseFromSlice(Config, allocator, json_str, .{});
defer parsed.deinit();
const config = parsed.value;
// config.name == "server", config.port == 8080, config.enabled == true
const parsed = try std.json.parseFromSlice(T, allocator, json_str, .{
.duplicate_field_behavior = .@"error", // .use_first | .use_last
.ignore_unknown_fields = true,
.max_value_len = 4096,
.parse_numbers = true,
});
| Zig 类型 | JSON 值 |
|---------|---------|
| bool | true, false |
| i32, u64 等 | number(或字符串,可选) |
| f32, f64 | number |
| []const u8 | string |
| []T | array |
| struct | object |
| ?T | value 或 null |
| union(enum) | 带 tag 的对象 |
| std.json.Value | 任意 JSON |
const Config = struct {
name: []const u8, // 引用了 parsed 的内存
tags: []const []const u8, // 同上
};
// ⚠️ parsed.deinit() 后这些字段不可用
// 如需长期持有:allocator.dupe()
// 使用 arena 简化生命周期
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
const parsed = try std.json.parseFromSliceLeaky(Config, arena.allocator(), json_str, .{});
// arena.deinit() 一次性释放所有内存
const Config = struct {
name: []const u8,
port: u16,
};
const config = Config{ .name = "server", .port = 8080 };
var buf: [256]u8 = undefined;
var writer: std.Io.Writer = .fixed(&buf);
try std.json.stringify(config, .{}, &writer);
const json = writer.buffered();
// {"name":"server","port":8080}
try std.json.stringify(config, .{ .whitespace = .indent_2 }, &writer);
// {
// "name": "server",
// "port": 8080
// }
try std.json.stringify(value, .{ .emit_null_optional_fields = false }, &writer);
const raw = \\{"users":[{"name":"Alice"}],"count":1};
const root = try std.json.parseFromSlice(std.json.Value, allocator, raw, .{});
defer root.deinit();
const obj = root.value.object;
const count = obj.get("count").?.integer;
const users = obj.get("users").?.array;
for (users) |user| {
const name = user.object.get("name").?.string;
}
var obj = std.json.ObjectMap.init(allocator);
try obj.put("name", std.json.Value{ .string = "Alice" });
try obj.put("age", std.json.Value{ .integer = 30 });
// 序列化
var buf: [256]u8 = undefined;
var writer: std.Io.Writer = .fixed(&buf);
try std.json.stringify(std.json.Value{ .object = obj }, .{}, &writer);
const Point = struct {
x: i32,
y: i32,
pub fn jsonStringify(self: Point, jws: *std.json.WriteStream(.{})) !void {
try jws.beginObject();
try jws.objectField("coordinates");
try jws.beginArray();
try jws.write(self.x);
try jws.write(self.y);
try jws.endArray();
try jws.endObject();
}
};
const std = @import("std");
const Config = struct {
name: []const u8,
version: []const u8,
};
const zon_str =
\\.{
\\ .name = "myapp",
\\ .version = "0.1.0",
\\}
;
const parsed = try std.zon.parseFromSlice(Config, allocator, zon_str, .{});
defer parsed.deinit();
// parsed.value.name == "myapp"
// 逐 token 扫描(避免将整个 JSON 加载到内存)
const file = try std.fs.cwd().openFile("large.json", .{});
defer file.close();
var buf_reader = std.io.bufferedReader(file.reader());
const reader = buf_reader.reader();
var scan_state = std.json.Scanner.init(allocator, reader.any());
defer scan_state.deinit();
while (true) {
const token = scan_state.next() orelse break;
switch (token) {
.object_begin => {},
.string => |s| { /* handle string */ },
.number => |n| { /* handle number */ },
else => {},
}
}
parsed.deinit() 释放引用内存 — 解析后 []const u8 字段引用的是 parsed 内部内存,deinit 后不可用parseFromSliceLeaky 配合 ArenaAllocator 省去逐字段拷贝parseFromSlice 会加载整个 JSON,超大文件使用 Scanner 流式处理integer 字段注意符号 — std.json.Value.integer 是 i64,无符号大数需额外处理.field = value 而非 "field": value,且键名不能加引号Q:parseFromSlice 和 parseFromSliceLeaky 区别?
A:前者返回 Parsed(T) 需要手动 deinit(),后者使用 arena 一次性释放,适合短期使用。
Q:如何处理超大 JSON?
A:用 std.json.Scanner 逐 token 处理,或者用流式 Reader 边读边解析。
Q:ZON 和 JSON 什么时候用哪个? A:Zig 项目配置用 ZON(build.zig.zon),外部 API 通信用 JSON。