From 7b1c9c3b639f0638fa03dddb8b932298baef2f73 Mon Sep 17 00:00:00 2001 From: Dave Gauer Date: Tue, 9 Mar 2021 20:04:43 -0500 Subject: add ex 55 unions --- exercises/55_unions.zig | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 exercises/55_unions.zig (limited to 'exercises/55_unions.zig') diff --git a/exercises/55_unions.zig b/exercises/55_unions.zig new file mode 100644 index 0000000..5e08aa1 --- /dev/null +++ b/exercises/55_unions.zig @@ -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}), + } +} -- cgit v1.2.3-70-g09d2