diff --git a/build.zig b/build.zig index 0a7b8b8..90d8a0b 100644 --- a/build.zig +++ b/build.zig @@ -404,6 +404,11 @@ const exercises = [_]Exercise{ .main_file = "081_anonymous_structs2.zig", .output = "x:205 y:187 radius:12", }, + .{ + .main_file = "082_anonymous_structs3.zig", + .output = "\"0\"(bool):true \"1\"(bool):false \"2\"(i32):42 \"3\"(f32):3.14159202e+00", + .hint = "This one is a challenge! But you have everything you need." + }, }; /// Check the zig version to make sure it can compile the examples properly. diff --git a/exercises/082_anonymous_structs3.zig b/exercises/082_anonymous_structs3.zig new file mode 100644 index 0000000..6b5fe04 --- /dev/null +++ b/exercises/082_anonymous_structs3.zig @@ -0,0 +1,125 @@ +// +// You can even create anonymous struct literals without field +// names: +// +// .{ +// false, +// @as(u32, 15); +// @as(i64, 67.12); +// } +// +// We call these "tuples", which is a term used by many +// programming languages for a data type with fields referenced +// by index order rather than name. To make this possible, the Zig +// compiler automatically assigns numeric field names 0, 1, 2, +// etc. to the struct. +// +// Since bare numbers are not legal identifiers (foo.0 is a +// syntax error), we have to quote them with the @"" syntax. +// Example: +// +// const foo = .{ true, false }; +// +// print("{} {}\n", .{foo.@"0", foo.@"1"}); +// +// The example above prints "true false". +// +// Hey, WAIT A SECOND... +// +// If a .{} thing is what the print function wants, do we need to +// break our "tuple" apart and put it in another one? No! It's +// redundant! This will print the same thing: +// +// print("{} {}\n", foo); +// +// Aha! So now we know that print() takes a "tuple". Things are +// really starting to come together now. +// +const print = @import("std").debug.print; + +pub fn main() void { + // A "tuple": + const foo = .{ + true, + false, + @as(i32, 42), + @as(f32, 3.141592), + }; + + // We'll be implementing this: + printTuple(foo); + + // This is just for fun, because we can: + const nothing = .{}; + print("\n", nothing); +} + +// Let's make our own generic "tuple" printer. This should take a +// "tuple" and print out each field in the following format: +// +// "name"(type):value +// +// Example: +// +// "0"(bool):true +// +// You'll be putting this together. But don't worry, everything +// you need is documented in the comments. +fn printTuple(tuple: anytype) void { + // 1. Get a list of fields in the input 'tuple' + // parameter. You'll need: + // + // @TypeOf() - takes a value, returns its type. + // + // @typeInfo() - takes a type, returns a TypeInfo union + // with fields specific to that type. + // + // The list of a struct type's fields can be found in + // TypeInfo's Struct.fields. + // + // Example: + // + // @typeInfo(Circle).Struct.fields + // + // This will be an array of StructFields. + const fields = ???; + + // 2. Loop through each field. This must be done at compile + // time. + // + // Hint: remember 'inline' loops? + // + for (fields) |field| { + // 3. Print the field's name, type, and value. + // + // Each 'field' in this loop is one of these: + // + // pub const StructField = struct { + // name: []const u8, + // field_type: type, + // default_value: anytype, + // is_comptime: bool, + // alignment: comptime_int, + // }; + // + // You'll need this builtin: + // + // @field(lhs: anytype, comptime field_name: []const u8) + // + // The first parameter is the value to be accessed, + // the second parameter is a string with the name of + // the field you wish to access. The value of the + // field is returned. + // + // Example: + // + // @field(foo, "x"); // returns the value at foo.x + // + // The first field should print as: "0"(bool):true + print("\"{s}\"({s}):{any} ", .{ + field.???, + field.???, + ???, + }); + } +} diff --git a/patches/patches/082_anonymous_structs3.patch b/patches/patches/082_anonymous_structs3.patch new file mode 100644 index 0000000..807e2f9 --- /dev/null +++ b/patches/patches/082_anonymous_structs3.patch @@ -0,0 +1,20 @@ +85c85 +< const fields = ???; +--- +> const fields = @typeInfo(@TypeOf(tuple)).Struct.fields; +92c92 +< for (fields) |field| { +--- +> inline for (fields) |field| { +116c116 +< // @field(foo, "x"); // returns the value at foo.x +--- +> // @field(foo, "x"); +120,122c120,122 +< field.???, +< field.???, +< ???, +--- +> field.name, +> field.field_type, +> @field(tuple, field.name),