在Zig中解析JSON对象数组时遇UnexpectedToken错误求助
Zig解析JSON数组报错UnexpectedToken的解决方法
我是Zig语言新手,尝试解析一个JSON文件,但相关文档较少。运行时出现如下错误,我推测是因为目标JSON文件是对象数组而非单个对象:
原代码
const std = @import("std"); pub const SearchIndexEntry = struct { task_id: []const u8, client_thumbprint: []const u8, search_item_timestamp: []const u8, search_item: []const u8, search_results: []const u8, search_results_captured: []const u8, sum_bundle: []const u8, num_outlier: []const u8, percent_complete: []const u8, p0: []const u8, p25: []const u8, p50: []const u8, p75: []const u8, p100: []const u8, mean: []const u8, std: []const u8, }; pub fn main() !void { const url = "https://storage.googleapis.com/owlrepo/v1/queries/search_item_listing.json"; var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); var client = std.http.Client{ .allocator = allocator }; defer client.deinit(); const uri = try std.Uri.parse(url); const headers = std.http.Client.Request.Headers{ .content_type = std.http.Client.Request.Headers.Value{ .override = "application/json", }, }; const server_header_buffer: []u8 = try allocator.alloc(u8, 8 * 1024 * 4); var req = try client.open(.GET, uri, std.http.Client.RequestOptions{ .server_header_buffer = server_header_buffer, .headers = headers, }); defer req.deinit(); try req.send(); try req.wait(); const json_str = try req.reader().readAllAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(json_str); // 报错位置 const data = try std.json.parseFromSlice(SearchIndexEntry, allocator, json_str, .{}); defer data.deinit(); defer std.debug.print("{any}", .{data}); }
报错信息
error: UnexpectedToken /home/a/dl/zig-dl/lib/std/json/static.zig:334:53: 0x123d778 in innerParse__anon_13392 (main) if (.object_begin != try source.next()) return error.UnexpectedToken; ^ /home/a/dl/zig-dl/lib/std/json/static.zig:149:19: 0x1152e34 in parseFromTokenSourceLeaky__anon_9602 (main) const value = try innerParse(T, allocator, scanner_or_reader, resolved_options); ^ /home/a/dl/zig-dl/lib/std/json/static.zig:116:20: 0x112a5d5 in parseFromTokenSource__anon_5642 (main) parsed.value = try parseFromTokenSourceLeaky(T, parsed.arena.allocator(), scanner_or_reader, options); ^ /home/a/dl/zig-dl/lib/std/json/static.zig:82:5: 0x111c5a1 in parseFromSlice__anon_3480 (main) return parseFromTokenSource(T, allocator, &scanner, options); ^ /home/a/c/owldepo/scrapper/main.zig:35:18: 0x1116cec in main (main) const data = try std.json.parseFromSlice(SearchIndexEntry, allocator, json_str, .{});
问题原因
你的推测完全正确:std.json.parseFromSlice传入的类型是单个SearchIndexEntry对象,解析器会预期JSON以{(对象起始符)开头,但目标JSON实际是[(数组起始符)开头的对象数组,因此触发UnexpectedToken错误。
解决方法
只需将解析目标类型改为数组[]SearchIndexEntry,同时补充一处内存释放避免泄漏:
修改后的完整代码
const std = @import("std"); pub const SearchIndexEntry = struct { task_id: []const u8, client_thumbprint: []const u8, search_item_timestamp: []const u8, search_item: []const u8, search_results: []const u8, search_results_captured: []const u8, sum_bundle: []const u8, num_outlier: []const u8, percent_complete: []const u8, p0: []const u8, p25: []const u8, p50: []const u8, p75: []const u8, p100: []const u8, mean: []const u8, std: []const u8, }; pub fn main() !void { const url = "https://storage.googleapis.com/owlrepo/v1/queries/search_item_listing.json"; var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); var client = std.http.Client{ .allocator = allocator }; defer client.deinit(); const uri = try std.Uri.parse(url); const headers = std.http.Client.Request.Headers{ .content_type = std.http.Client.Request.Headers.Value{ .override = "application/json", }, }; const server_header_buffer: []u8 = try allocator.alloc(u8, 8 * 1024 * 4); defer allocator.free(server_header_buffer); // 补充内存释放 var req = try client.open(.GET, uri, std.http.Client.RequestOptions{ .server_header_buffer = server_header_buffer, .headers = headers, }); defer req.deinit(); try req.send(); try req.wait(); const json_str = try req.reader().readAllAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(json_str); // 修改解析目标为数组类型 const data = try std.json.parseFromSlice([]SearchIndexEntry, allocator, json_str, .{}); defer data.deinit(); // 示例:打印数组长度和第一个元素 std.debug.print("总条目数:{d}\n", .{data.value.len}); if (data.value.len > 0) { std.debug.print("第一个条目详情:{any}\n", .{data.value[0]}); } }
额外提示
- 使用
arena分配器时,虽然最终会通过arena.deinit()释放所有内存,但显式释放临时缓冲区是良好的编码习惯。 - 解析数组后,可通过
data.value直接访问数组元素,支持索引遍历或for循环迭代。
内容的提问来源于stack exchange,提问作者Aria Lopez
相关产品推荐
相关产品推荐

