如何在Zig中在编译期获取字段的值

huangapple go评论92阅读模式
英文:

How to get the field value in comptime in zig

问题

I want to make a deserializer in Zig. Now I could iterate the field information in comptime. But I want to get the field default value in struct. Is there a way to get them? For example, I want to get the zzzz's value 100 in getIntOrDefault.

  1. const std = @import("std");
  2. const meta = std.meta;
  3. const trait = meta.trait;
  4. const assert = std.debug.assert;
  5. pub fn deserializeInto(ptr: anytype) !void {
  6. const T = @TypeOf(ptr);
  7. comptime assert(trait.is(.Pointer)(T));
  8. const C = comptime meta.Child(T);
  9. ptr.* = switch (C) {
  10. []const u8 => "test string",
  11. else => switch (@typeInfo(C)) {
  12. .Struct => try deserializeStruct(C),
  13. .Int => try getIntOrDefault(C),
  14. else => @compileError("Unsupported deserialization type " ++ @typeName(C) ++ "\n"),
  15. },
  16. };
  17. }
  18. pub fn getIntOrDefault(comptime T: type) !T {
  19. return 2;
  20. }
  21. pub fn deserializeStruct(comptime T: type) !T {
  22. var value: T = undefined;
  23. inline for (meta.fields(T)) |struct_field| {
  24. try deserializeInto(&@field(value, struct_field.name));
  25. }
  26. return value;
  27. }
  28. pub fn main() !void {
  29. const T = struct {
  30. wwww: []const u8,
  31. zzzz: u32 = 100,
  32. };
  33. var v: T = undefined;
  34. try deserializeInto(&v);
  35. std.debug.print("zzzz value is {d}\n", .{v.zzzz});
  36. }

(Note: Code comments and non-translatable parts have been removed as per your request.)

英文:

I want to make a deserializer in Zig. Now I could iterate the field information in comptime. But I want to get the field default value in struct. Is there a way to get them? For example, I want to get the zzzz's value 100 in getIntOrDefault.

  1. const std = @import("std");
  2. const meta = std.meta;
  3. const trait = meta.trait;
  4. const assert = std.debug.assert;
  5. pub fn deserializeInto(ptr: anytype) !void {
  6. const T = @TypeOf(ptr);
  7. comptime assert(trait.is(.Pointer)(T));
  8. const C = comptime meta.Child(T);
  9. ptr.* = switch (C) {
  10. []const u8 => "test string",
  11. else => switch (@typeInfo(C)) {
  12. .Struct => try deserializeStruct(C),
  13. .Int => try getIntOrDefault(C),
  14. else => @compileError("Unsupported deserialization type " ++ @typeName(C) ++ "\n"),
  15. },
  16. };
  17. }
  18. pub fn getIntOrDefault(comptime T: type) !T {
  19. return 2;
  20. }
  21. pub fn deserializeStruct(comptime T: type) !T {
  22. var value: T = undefined;
  23. inline for (meta.fields(T)) |struct_field| {
  24. try deserializeInto(&@field(value, struct_field.name));
  25. }
  26. return value;
  27. }
  28. pub fn main() !void {
  29. const T = struct {
  30. wwww: []const u8,
  31. zzzz: u32 = 100,
  32. };
  33. var v: T = undefined;
  34. try deserializeInto(&v);
  35. std.debug.print("zzzz value is {d}\n", .{v.zzzz});
  36. }

答案1

得分: 3

默认值可通过@typeInfo(T).Struct.fields[...].default_value访问,但它存储为对anyopaque的指针,除非使用@ptrCast进行类型转换,否则无法对其进行解引用,示例如下:

  1. const std = @import("std");
  2. pub fn main() !void {
  3. const TestStruct = struct {
  4. foo: u32 = 123,
  5. };
  6. std.log.info("{}", .{ TestStruct{} });
  7. const foo_field = @typeInfo(TestStruct).Struct.fields[0];
  8. std.log.info("field name: {}", .{ foo_field.name });
  9. if (foo_field.default_value) |dvalue| {
  10. const dvalue_aligned: *const align(foo_field.alignment) anyopaque = @alignCast(dvalue);
  11. const value = @as(*const foo_field.type, @ptrCast(dvalue_aligned)).*;
  12. std.log.info("default value: {}", .{ value });
  13. }
  14. }

打印结果:

  1. $ zig build run
  2. info: main.main.TestStruct{ .foo = 123 }
  3. info: field name: foo
  4. info: default value: 123

在Zig 0.10版本中,@ptrCast的用法如下:

  1. const dvalue_aligned = @alignCast(foo_field.alignment, dvalue);
  2. const value = @ptrCast(*const foo_field.type, dvalue_aligned).*;
  3. std.log.info("default value: {}", .{ value });
英文:

Zig 0.11+

The default value is available as @typeInfo(T).Struct.fields[...].default_value. But it is stored as a pointer to anyopaque, you won't be able to dereference it, unless you cast it with @ptrCast like that:

  1. const std = @import("std");
  2. pub fn main() !void {
  3. const TestStruct = struct {
  4. foo: u32 = 123,
  5. };
  6. std.log.info("{}", .{ TestStruct{} });
  7. const foo_field = @typeInfo(TestStruct).Struct.fields[0];
  8. std.log.info("field name: {s}", .{ foo_field.name });
  9. if (foo_field.default_value) |dvalue| {
  10. const dvalue_aligned: *const align(foo_field.alignment) anyopaque = @alignCast(dvalue);
  11. const value = @as(*const foo_field.type, @ptrCast(dvalue_aligned)).*;
  12. std.log.info("default value: {}", .{ value });
  13. }
  14. }

It prints:

  1. $ zig build run
  2. info: main.main.TestStruct{ .foo = 123 }
  3. info: field name: foo
  4. info: default value: 123

Zig 0.10

The @ptrCast usage used to look like this:

  1. const dvalue_aligned = @alignCast(foo_field.alignment, dvalue);
  2. const value = @ptrCast(*const foo_field.type, dvalue_aligned).*;
  3. std.log.info("default value: {}", .{ value });

huangapple
  • 本文由 发表于 2023年5月25日 15:03:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76329659.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定