mirror of
https://codeberg.org/andyscott/ziglings.git
synced 2024-12-22 14:03:10 -05:00
Add ex51 values
This commit is contained in:
parent
28791f0cb8
commit
4f9c8f57ba
3 changed files with 196 additions and 1 deletions
|
@ -264,7 +264,10 @@ const exercises = [_]Exercise{
|
||||||
.main_file = "50_no_value.zig",
|
.main_file = "50_no_value.zig",
|
||||||
.output = "That is not dead which can eternal lie / And with strange aeons even death may die.",
|
.output = "That is not dead which can eternal lie / And with strange aeons even death may die.",
|
||||||
},
|
},
|
||||||
// 51 pass-by-value and const fn params
|
.{
|
||||||
|
.main_file = "51_values.zig",
|
||||||
|
.output = "1:false!. 2:true!. 3:true!. XP before:0, after:200.",
|
||||||
|
},
|
||||||
// 52 slices!
|
// 52 slices!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
180
exercises/51_values.zig
Normal file
180
exercises/51_values.zig
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
//
|
||||||
|
// If you thought the last exercise was a deep dive, hold onto your
|
||||||
|
// hat because we are about to descend into the computer's molten
|
||||||
|
// core.
|
||||||
|
//
|
||||||
|
// (Shouting) DOWN HERE, THE BITS AND BYTES FLOW FROM RAM TO THE CPU
|
||||||
|
// LIKE A HOT, DENSE FLUID. THE FORCES ARE INCREDIBLE. BUT HOW DOES
|
||||||
|
// ALL OF THIS RELATE TO THE DATA IN OUR ZIG PROGRAMS? LET'S HEAD
|
||||||
|
// BACK UP TO THE TEXT EDITOR AND FIND OUT.
|
||||||
|
//
|
||||||
|
// (Conversational) Ah, that's better. Now we can look at some
|
||||||
|
// familiar Zig code!
|
||||||
|
//
|
||||||
|
// @import() adds the imported code to your own. In this case,
|
||||||
|
// compiled code from the standard library is compiled in with your
|
||||||
|
// program. It is loaded into RAM with the code you write when it
|
||||||
|
// runs. And that thing we give a const name? That's a struct!
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// Remember our old RPG Character struct? A struct is really just a
|
||||||
|
// very convenient way to deal with memory. These fields (gold,
|
||||||
|
// health, experience) are all values of a particular size. Add them
|
||||||
|
// together and you have the size of the struct as a whole.
|
||||||
|
|
||||||
|
const Character = struct {
|
||||||
|
gold: u32 = 0,
|
||||||
|
health: u8 = 100,
|
||||||
|
experience: u32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Here we create a character called "the_narrator" that is a constant
|
||||||
|
// (immutable) instance of a Character struct. It is stored in your
|
||||||
|
// program as data, and like the instruction code, it is loaded into
|
||||||
|
// RAM when your program runs. The relative location of this data in
|
||||||
|
// memory is hard-coded and neither the address nor the value changes.
|
||||||
|
|
||||||
|
const the_narrator = Character{
|
||||||
|
.gold = 12,
|
||||||
|
.health = 99,
|
||||||
|
.experience = 9000,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This "global_wizard" character is very similar. The address for
|
||||||
|
// this data won't change, but the data itself can since this is a var
|
||||||
|
// and not a const.
|
||||||
|
|
||||||
|
var global_wizard = Character{};
|
||||||
|
|
||||||
|
// A function is instruction code at a particular address. Function
|
||||||
|
// parameters in Zig are always immutable. They are stored in "the
|
||||||
|
// stack". A stack is a type of data structure and "the stack" is a
|
||||||
|
// specific bit of RAM reserved for your program. The CPU has special
|
||||||
|
// support for adding and removing things from "the stack", so it is
|
||||||
|
// an extremely efficient place for memory storage.
|
||||||
|
//
|
||||||
|
// Also, when a function executes, the input arguments are often
|
||||||
|
// loaded into the beating heart of the CPU itself in registers.
|
||||||
|
//
|
||||||
|
// Our main() function here has no input parameters, but it will have
|
||||||
|
// a stack entry (called a "frame").
|
||||||
|
|
||||||
|
pub fn main() void {
|
||||||
|
|
||||||
|
// Here, the "glorp" character will be allocated on the stack
|
||||||
|
// because each instance of glorp is mutable and therefore unique
|
||||||
|
// to the invocation of this function.
|
||||||
|
|
||||||
|
var glorp = Character{
|
||||||
|
.gold = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
// However, this "skull_farmer" character will be put in the
|
||||||
|
// global immutable data even though it's defined in a function.
|
||||||
|
// Since it's immutable, all invocations of the function can share
|
||||||
|
// this one value.
|
||||||
|
|
||||||
|
const skull_farmer = Character{};
|
||||||
|
|
||||||
|
// The "reward_xp" value is interesting. It's a constant value, so
|
||||||
|
// it could go with other global data. But being such a small
|
||||||
|
// value, it may also simply be inlined as a literal value in your
|
||||||
|
// instruction code where it is used. It's up to the compiler.
|
||||||
|
|
||||||
|
const reward_xp: u32 = 200;
|
||||||
|
|
||||||
|
// Now let's circle back around to that "std" struct we imported
|
||||||
|
// at the top. Since it's just a regular Zig value once it's
|
||||||
|
// imported, we can also assign new names for its fields. The
|
||||||
|
// "debug" field refers to another struct. And "print" is a public
|
||||||
|
// function namespaced within THAT struct.
|
||||||
|
//
|
||||||
|
// Let's assign the std.debug.print function to a const named
|
||||||
|
// "print" so that we can use this new name later!
|
||||||
|
|
||||||
|
const print = ???;
|
||||||
|
|
||||||
|
// Now let's look at assigning and pointing to values in Zig.
|
||||||
|
//
|
||||||
|
// We'll try three different ways of making a new name to access
|
||||||
|
// our glorp Character and change one of its values.
|
||||||
|
//
|
||||||
|
// "glorp_access1" is incorrectly named! We asked Zig to set aside
|
||||||
|
// memory for another Character struct. So when we assign glorp to
|
||||||
|
// glorp_access1 here, we're actually assigning all of the fields
|
||||||
|
// to make a copy! Now we have two separate characters.
|
||||||
|
//
|
||||||
|
// You don't need to fix this. But notice what gets printed in
|
||||||
|
// your program's output for this one compared to the other two
|
||||||
|
// assignments below!
|
||||||
|
|
||||||
|
var glorp_access1: Character = glorp;
|
||||||
|
glorp_access1.gold = 111;
|
||||||
|
print("1:{}!. ", .{glorp.gold == glorp_access1.gold});
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
//
|
||||||
|
// If we tried to do this with a const Character instead of a
|
||||||
|
// var, changing the gold field would give us a compiler error
|
||||||
|
// because const values are immutable!
|
||||||
|
//
|
||||||
|
// "glorp_access2" will do what we want. It points to the original
|
||||||
|
// glorp's address. Also remember that we get one implicit
|
||||||
|
// dereference with struct fields, so accessing the "gold" field
|
||||||
|
// from glorp_access2 looks just like accessing it from glorp
|
||||||
|
// itself.
|
||||||
|
|
||||||
|
var glorp_access2: *Character = &glorp;
|
||||||
|
glorp_access2.gold = 222;
|
||||||
|
print("2:{}!. ", .{glorp.gold == glorp_access2.gold});
|
||||||
|
|
||||||
|
// "glorp_access3" is interesting. It's also a pointer, but it's a
|
||||||
|
// const. Won't that disallow changing the gold value? No! As you
|
||||||
|
// may recall from our earlier pointer experiments, a constant
|
||||||
|
// pointer can't change what it's pointing AT, but the value at
|
||||||
|
// the address it points to is still mutable! So we CAN change it.
|
||||||
|
|
||||||
|
const glorp_access3: *Character = &glorp;
|
||||||
|
glorp_access3.gold = 333;
|
||||||
|
print("3:{}!. ", .{glorp.gold == glorp_access3.gold});
|
||||||
|
|
||||||
|
// Passing arguments to functions is pretty much exactly like
|
||||||
|
// making an assignment to a const (since Zig enforces that ALL
|
||||||
|
// function parameters are const).
|
||||||
|
//
|
||||||
|
// Knowing that, see if you can make levelUp() work as expected -
|
||||||
|
// it should add the specified amount to the supplied character's
|
||||||
|
// experience points:
|
||||||
|
|
||||||
|
print("XP before:{}, ", .{glorp.experience});
|
||||||
|
|
||||||
|
levelUp(glorp, reward_xp);
|
||||||
|
|
||||||
|
print("after:{}.\n", .{glorp.experience});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn levelUp(character_access: Character, xp: u32) void {
|
||||||
|
character_access.experience += xp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And there's more!
|
||||||
|
//
|
||||||
|
// Data segments (allocated at compile time) and "the stack"
|
||||||
|
// (allocated at run time) aren't the only places where program data
|
||||||
|
// can be stored in memory. They're just the most efficient. Sometimes
|
||||||
|
// we don't know how much memory our program will need until the
|
||||||
|
// program is running. Also, there is a limit to the size of stack
|
||||||
|
// memory allotted to programs (often set by your operating system).
|
||||||
|
// For these occasions, we have "the heap".
|
||||||
|
//
|
||||||
|
// You can use as much heap memory as you like (within physical
|
||||||
|
// limitations, of course), but it's much less efficient to manage
|
||||||
|
// because there is no built-in CPU support for adding and removing
|
||||||
|
// items as we have with the stack. Also, depending on the type of
|
||||||
|
// allocation, your program MAY have to do expensive work to manage
|
||||||
|
// the use of heap memory. We'll learn about heap allocators later.
|
||||||
|
//
|
||||||
|
// Whew! This has been a lot of information. You'll be pleased to know
|
||||||
|
// that the next exercise gets us back to learning Zig language
|
||||||
|
// features we can use right away to do more things!
|
12
patches/patches/51_values.patch
Normal file
12
patches/patches/51_values.patch
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
96c96
|
||||||
|
< const print = ???;
|
||||||
|
---
|
||||||
|
> const print = std.debug.print;
|
||||||
|
152c152
|
||||||
|
< levelUp(glorp, reward_xp);
|
||||||
|
---
|
||||||
|
> levelUp(&glorp, reward_xp);
|
||||||
|
157c157
|
||||||
|
< fn levelUp(character_access: Character, xp: u32) void {
|
||||||
|
---
|
||||||
|
> fn levelUp(character_access: *Character, xp: u32) void {
|
Loading…
Reference in a new issue