063_labels.zig 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //
  2. // Loop bodies are blocks, which are also expressions. We've seen
  3. // how they can be used to evaluate and return values. To further
  4. // expand on this concept, it turns out we can also give names to
  5. // blocks by applying a 'label':
  6. //
  7. // my_label: { ... }
  8. //
  9. // Once you give a block a label, you can use 'break' to exit
  10. // from that block.
  11. //
  12. // outer_block: { // outer block
  13. // while (true) { // inner block
  14. // break :outer_block;
  15. // }
  16. // unreachable;
  17. // }
  18. //
  19. // As we've just learned, you can return a value using a break
  20. // statement. Does that mean you can return a value from any
  21. // labeled block? Yes it does!
  22. //
  23. // const foo = make_five: {
  24. // const five = 1 + 1 + 1 + 1 + 1;
  25. // break :make_five five;
  26. // };
  27. //
  28. // Labels can also be used with loops. Being able to break out of
  29. // nested loops at a specific level is one of those things that
  30. // you won't use every day, but when the time comes, it's
  31. // incredibly convenient. Being able to return a value from an
  32. // inner loop is sometimes so handy, it almost feels like cheating
  33. // (and can help you avoid creating a lot of temporary variables).
  34. //
  35. // const bar: u8 = two_loop: while (true) {
  36. // while (true) {
  37. // break :two_loop 2;
  38. // }
  39. // } else 0;
  40. //
  41. // In the above example, the break exits from the outer loop
  42. // labeled "two_loop" and returns the value 2. The else clause is
  43. // attached to the outer two_loop and would be evaluated if the
  44. // loop somehow ended without the break having been called.
  45. //
  46. // Finally, you can also use block labels with the 'continue'
  47. // statement:
  48. //
  49. // my_while: while (true) {
  50. // continue :my_while;
  51. // }
  52. //
  53. const print = @import("std").debug.print;
  54. // As mentioned before, we'll soon understand why these two
  55. // numbers don't need explicit types. Hang in there!
  56. const ingredients = 4;
  57. const foods = 4;
  58. const Food = struct {
  59. name: []const u8,
  60. requires: [ingredients]bool,
  61. };
  62. // Chili Macaroni Tomato Sauce Cheese
  63. // ------------------------------------------------------
  64. // Mac & Cheese x x
  65. // Chili Mac x x
  66. // Pasta x x
  67. // Cheesy Chili x x
  68. // ------------------------------------------------------
  69. const menu: [foods]Food = [_]Food{
  70. Food{
  71. .name = "Mac & Cheese",
  72. .requires = [ingredients]bool{ false, true, false, true },
  73. },
  74. Food{
  75. .name = "Chili Mac",
  76. .requires = [ingredients]bool{ true, true, false, false },
  77. },
  78. Food{
  79. .name = "Pasta",
  80. .requires = [ingredients]bool{ false, true, true, false },
  81. },
  82. Food{
  83. .name = "Cheesy Chili",
  84. .requires = [ingredients]bool{ true, false, false, true },
  85. },
  86. };
  87. pub fn main() void {
  88. // Welcome to Cafeteria USA! Choose your favorite ingredients
  89. // and we'll produce a delicious meal.
  90. //
  91. // Cafeteria Customer Note: Not all ingredient combinations
  92. // make a meal. The default meal is macaroni and cheese.
  93. //
  94. // Software Developer Note: Hard-coding the ingredient
  95. // numbers (based on array position) will be fine for our
  96. // tiny example, but it would be downright criminal in a real
  97. // application!
  98. const wanted_ingredients = [_]u8{ 0, 3 }; // Chili, Cheese
  99. // Look at each Food on the menu...
  100. const meal = food_loop: for (menu) |food| {
  101. // Now look at each required ingredient for the Food...
  102. for (food.requires, 0..) |required, required_ingredient| {
  103. // This ingredient isn't required, so skip it.
  104. if (!required) continue;
  105. // See if the customer wanted this ingredient.
  106. // (Remember that want_it will be the index number of
  107. // the ingredient based on its position in the
  108. // required ingredient list for each food.)
  109. const found = for (wanted_ingredients) |want_it| {
  110. if (required_ingredient == want_it) break true;
  111. } else false;
  112. // We did not find this required ingredient, so we
  113. // can't make this Food. Continue the outer loop.
  114. if (!found) continue :food_loop;
  115. }
  116. // If we get this far, the required ingredients were all
  117. // wanted for this Food.
  118. //
  119. // Please return this Food from the loop.
  120. break;
  121. };
  122. // ^ Oops! We forgot to return Mac & Cheese as the default
  123. // Food when the requested ingredients aren't found.
  124. print("Enjoy your {s}!\n", .{meal.name});
  125. }
  126. // Challenge: You can also do away with the 'found' variable in
  127. // the inner loop. See if you can figure out how to do that!