mirror of
				https://codeberg.org/ziglings/exercises.git
				synced 2025-10-30 10:15:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			77 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Zig
		
	
	
	
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Zig
		
	
	
	
	
	
| //
 | |
| // 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}),
 | |
|     }
 | |
| }
 | 
