1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
//
// You can even create anonymous struct literals without field
// names:
//
// .{
// false,
// @as(u32, 15),
// @as(f64, 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: [:0]const u8,
// type: type,
// default_value_ptr: ?*const anyopaque,
// is_comptime: bool,
// alignment: comptime_int,
// };
//
// Note we will learn about 'anyopaque' type later
//
// 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
//
// Hint: Be careful! If your 'lhs' is a type, @field() looks
// for declarations. If it's a value, it looks for data.
//
print("\"{s}\"({any}):{any} ", .{
field.???,
field.???,
???,
});
}
}
|