|
@@ -0,0 +1,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 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}),
|
|
|
+ }
|
|
|
+}
|