mirror of
https://codeberg.org/andyscott/ziglings.git
synced 2024-12-22 06:03:09 -05:00
Added ex063 labels
This commit is contained in:
parent
e608e41cc7
commit
cc269968ea
4 changed files with 156 additions and 5 deletions
11
README.md
11
README.md
|
@ -133,11 +133,12 @@ Planned exercises:
|
|||
* [x] Slices
|
||||
* [x] Many-item pointers
|
||||
* [x] Unions
|
||||
* [ ] Numeric types (integers, floats)
|
||||
* [ ] Labelled blocks and loops
|
||||
* [ ] Loops as expressions
|
||||
* [ ] Comptime
|
||||
* [ ] Inline loops (how to DEMO this?)
|
||||
* [x] Numeric types (integers, floats)
|
||||
* [x] Labelled blocks and loops
|
||||
* [x] Loops as expressions
|
||||
* [ ] Builtins
|
||||
* [ ] Comptime (!)
|
||||
* [ ] Inline loops
|
||||
* [ ] Anonymous structs
|
||||
* [ ] Sentinel termination
|
||||
* [ ] Vectors
|
||||
|
|
|
@ -318,6 +318,10 @@ const exercises = [_]Exercise{
|
|||
.main_file = "062_loop_expressions.zig",
|
||||
.output = "Current language: Zig",
|
||||
},
|
||||
.{
|
||||
.main_file = "063_labels.zig",
|
||||
.output = "Enjoy your Cheesy Chili!",
|
||||
},
|
||||
};
|
||||
|
||||
/// Check the zig version to make sure it can compile the examples properly.
|
||||
|
|
140
exercises/063_labels.zig
Normal file
140
exercises/063_labels.zig
Normal file
|
@ -0,0 +1,140 @@
|
|||
//
|
||||
// Loop bodies are blocks, which are also expressions. We've seen
|
||||
// how they can be used to evaluate and return values. To further
|
||||
// expand on this concept, it turns out we can also give names to
|
||||
// blocks by applying a 'label':
|
||||
//
|
||||
// my_label: { ... }
|
||||
//
|
||||
// Once you give a block a label, you can use 'break' to exit
|
||||
// from that block.
|
||||
//
|
||||
// outer_block: { // outer block
|
||||
// while (true) { // inner block
|
||||
// break :outer_block;
|
||||
// }
|
||||
// unreachable;
|
||||
// }
|
||||
//
|
||||
// As we've just learned, you can return a value using a break
|
||||
// statement. Does that mean you can return a value from any
|
||||
// labeled block? Yes it does!
|
||||
//
|
||||
// const foo = make_five: {
|
||||
// const five = 1 + 1 + 1 + 1 + 1;
|
||||
// break :make_five five;
|
||||
// };
|
||||
//
|
||||
// Labels can also be used with loops. Being able to break out of
|
||||
// nested loops at a specific level is one of those things that
|
||||
// you won't use every day, but when the time comes, it's
|
||||
// incredibly convenient. Being able to return a value from an
|
||||
// inner loop is sometimes so handy, it almost feels like cheating
|
||||
// (and can help you avoid creating a lot of temporary variables).
|
||||
//
|
||||
// const bar: u8 = two_loop: while (true) {
|
||||
// while (true) {
|
||||
// break :two_loop 2;
|
||||
// }
|
||||
// } else 0;
|
||||
//
|
||||
// In the above example, the break exits from the outer loop
|
||||
// labeled "two_loop" and returns the value 2. The else clause is
|
||||
// attached to the outer two_loop and would be evaluated if the
|
||||
// loop somehow ended without the break having been called.
|
||||
//
|
||||
// Finally, you can also use block labels with the 'continue'
|
||||
// statement:
|
||||
//
|
||||
// my_while: while (true) {
|
||||
// continue :my_while;
|
||||
// }
|
||||
//
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
// As mentioned before, we'll soon understand why these two
|
||||
// numbers don't need explicit types. Hang in there!
|
||||
const ingredients = 4;
|
||||
const foods = 4;
|
||||
|
||||
const Food = struct {
|
||||
name: []const u8,
|
||||
requires: [ingredients]bool,
|
||||
};
|
||||
|
||||
// Chili Macaroni Tomato Sauce Cheese
|
||||
// ------------------------------------------------------
|
||||
// Mac & Cheese x x
|
||||
// Chili Mac x x
|
||||
// Pasta x x
|
||||
// Cheesy Chili x x
|
||||
// ------------------------------------------------------
|
||||
|
||||
const menu: [foods]Food = [_]Food{
|
||||
Food{
|
||||
.name = "Mac & Cheese",
|
||||
.requires = [ingredients]bool{ false, true, false, true },
|
||||
},
|
||||
Food{
|
||||
.name = "Chili Mac",
|
||||
.requires = [ingredients]bool{ true, true, false, false },
|
||||
},
|
||||
Food{
|
||||
.name = "Pasta",
|
||||
.requires = [ingredients]bool{ false, true, true, false },
|
||||
},
|
||||
Food{
|
||||
.name = "Cheesy Chili",
|
||||
.requires = [ingredients]bool{ true, false, false, true },
|
||||
},
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
// Welcome to Cafeteria USA! Choose your favorite ingredients
|
||||
// and we'll produce a delicious meal.
|
||||
//
|
||||
// Cafeteria Customer Note: Not all ingredient combinations
|
||||
// make a meal. The default meal is macaroni and cheese.
|
||||
//
|
||||
// Software Developer Note: Hard-coding the ingredient
|
||||
// numbers (based on array position) will be fine for our
|
||||
// tiny example, but it would be downright criminal in a real
|
||||
// application!
|
||||
const wanted_ingredients = [_]u8{ 0, 3 }; // Chili, Cheese
|
||||
|
||||
// Look at each Food on the menu...
|
||||
var meal = food_loop: for (menu) |food| {
|
||||
|
||||
// Now look at each required ingredient for the Food...
|
||||
for (food.requires) |required, required_ingredient| {
|
||||
|
||||
// This ingredient isn't required, so skip it.
|
||||
if (!required) continue;
|
||||
|
||||
// See if the customer wanted this ingredient.
|
||||
// (Remember that want_it will be the index number of
|
||||
// the ingredient based on its position in the
|
||||
// required ingredient list for each food.)
|
||||
var found = for (wanted_ingredients) |want_it| {
|
||||
if (required_ingredient == want_it) break true;
|
||||
} else false;
|
||||
|
||||
// We did not find this required ingredient, so we
|
||||
// can't make this Food. Continue the outer loop.
|
||||
if (!found) continue :food_loop;
|
||||
}
|
||||
|
||||
// If we get this far, the required ingredients were all
|
||||
// wanted for this Food.
|
||||
//
|
||||
// Please return this Food from the loop.
|
||||
break;
|
||||
};
|
||||
// ^ Oops! We forgot to return Mac & Cheese as the default
|
||||
// Food when the requested ingredients aren't found.
|
||||
|
||||
print("Enjoy your {s}!\n", .{meal.name});
|
||||
}
|
||||
|
||||
// Challenge: You can also do away with the 'found' variable in
|
||||
// the inner loop. See if you can figure out how to do that!
|
6
patches/patches/063_labels.patch
Normal file
6
patches/patches/063_labels.patch
Normal file
|
@ -0,0 +1,6 @@
|
|||
132,133c131,132
|
||||
< break;
|
||||
< };
|
||||
---
|
||||
> break food;
|
||||
> } else menu[0];
|
Loading…
Reference in a new issue