You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:15:57