mirror of
				https://codeberg.org/ziglings/exercises.git
				synced 2025-11-04 04:35:38 +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}),
 | 
						|
    }
 | 
						|
}
 |