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
|
//
// A union lets you store different types and sizes of data at
// the same memory address. How is this possible? The compiler
// sets aside enough memory for the largest thing you might want
// to store.
//
// In this example, an instance of Foo always takes up u64 of
// space in memory even if you're currently storing a u8.
//
// const Foo = union {
// small: u8,
// medium: u32,
// large: u64,
// };
//
// The syntax looks just like a struct, but a Foo can only hold a
// small OR a medium OR a large value. Once a field becomes
// active, the other inactive fields cannot be accessed. To
// change active fields, assign a whole new instance:
//
// var f = Foo{ .small = 5 };
// f.small += 5; // OKAY
// f.medium = 5432; // ERROR!
// f = Foo{ .medium = 5432 }; // OKAY
//
// Unions can save space in memory because they let you "re-use"
// a space in memory. They also provide a sort of primitive
// polymorphism. Here fooBar() can take a Foo no matter what size
// of unsigned integer it holds:
//
// fn fooBar(f: Foo) void { ... }
//
// Oh, but how does fooBar() know which field is active? Zig has
// a neat way of keeping track, but for now, we'll just have to
// do it manually.
//
// Let's see if we can get this program working!
//
const std = @import("std");
// We've just started writing a simple ecosystem simulation.
// Insects will be represented by either bees or ants. Bees store
// the number of flowers they've visited that day and ants just
// store whether or not they're still alive.
const Insect = union {
flowers_visited: u16,
still_alive: bool,
};
// Since we need to specify the type of insect, we'll use an
// enum (remember those?).
const AntOrBee = enum { a, b };
pub fn main() void {
// We'll just make one bee and one ant to test them out:
var ant = Insect{ .still_alive = true };
var bee = Insect{ .flowers_visited = 15 };
std.debug.print("Insect report! ", .{});
// Oops! We've made a mistake here.
printInsect(ant, AntOrBee.c);
printInsect(bee, AntOrBee.c);
std.debug.print("\n", .{});
}
// Eccentric Doctor Zoraptera says that we can only use one
// function to print our insects. Doctor Z is small and sometimes
// inscrutable but we do not question her.
fn printInsect(insect: Insect, what_it_is: AntOrBee) void {
switch (what_it_is) {
.a => std.debug.print("Ant alive is: {}. ", .{insect.still_alive}),
.b => std.debug.print("Bee visited {} flowers. ", .{insect.flowers_visited}),
}
}
|