Sure there is! In Zig you can declare identifiers that contain character sequences that would otherwise be invalid if you wrap the names in @"..."
: Documentation - The Zig Programming Language
This works for struct field names too, and you can access those fields using the same @"..."
syntax, or the @field()
builtin:
$ cat field.zig
const std = @import("std");
const FancyName = struct {
@"field$name": []const u8,
};
pub fn main() void {
const fns: FancyName = .{ .@"field$name" = "test" };
// both of these do the same thing
std.debug.print("using @\"...\": {s}\n", .{fns.@"field$name"});
std.debug.print("using @field(): {s}\n", .{@field(fns, "field$name")});
}
$ zig build-exe field.zig && ./field
using @"...": test
using @field(): test
So, for your example above, you can use this code:
$ cat json.zig
const std = @import("std");
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
const Response = struct {
headers: struct {
Host: []const u8,
@"User-Agent": []const u8,
},
};
const input =
\\ {
\\ "headers": {
\\ "Accept": "application/vnd.github.v3+json",
\\ "Host": "httpbin.org",
\\ "User-Agent": "my http client",
\\ "X-Amzn-Trace-Id": "Root=1-632f00bb-04724a8831e8b65c47175bba"
\\ } }
;
var stream = std.json.TokenStream.init(input);
const resp = try std.json.parse(Response, &stream, .{
.allocator = allocator,
.ignore_unknown_fields = true,
});
std.log.info("Host: {s}", .{resp.headers.Host});
std.log.info("User-Agent: {s}", .{resp.headers.@"User-Agent"});
}
$ zig build-exe json.zig && ./json
info: Host: httpbin.org
info: User-Agent: my http client