101_for5.zig 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. //
  2. // The 'for' loop is not just limited to looping over one or two
  3. // items. Let's try an example with a whole bunch!
  4. //
  5. // But first, there's one last thing we've avoided mentioning
  6. // until now: The special range that leaves off the last value:
  7. //
  8. // for ( things, 0.. ) |t, i| { ... }
  9. //
  10. // That's how we tell Zig that we want to get a numeric value for
  11. // every item in "things", starting with 0.
  12. //
  13. // A nice feature of these index ranges is that you can have them
  14. // start with any number you choose. The first value of "i" in
  15. // this example will be 500, then 501, 502, etc.:
  16. //
  17. // for ( things, 500.. ) |t, i| { ... }
  18. //
  19. // Remember our RPG characters? They had the following
  20. // properties, which we stored in a struct type:
  21. //
  22. // class
  23. // gold
  24. // experience
  25. //
  26. // What we're going to do now is store the same RPG character
  27. // data, but in a separate array for each property.
  28. //
  29. // It might look a little awkward, but let's bear with it.
  30. //
  31. // We've started writing a program to print a numbered list of
  32. // characters with each of their properties, but it needs a
  33. // little help:
  34. //
  35. const std = @import("std");
  36. const print = std.debug.print;
  37. // This is the same character role enum we've seen before.
  38. const Role = enum {
  39. wizard,
  40. thief,
  41. bard,
  42. warrior,
  43. };
  44. pub fn main() void {
  45. // Here are the three "property" arrays:
  46. const roles = [4]Role{ .wizard, .bard, .bard, .warrior };
  47. const gold = [4]u16{ 25, 11, 5, 7392 };
  48. const experience = [4]u8{ 40, 17, 55, 21 };
  49. // We would like to number our list starting with 1, not 0.
  50. // How do we do that?
  51. for (roles, gold, experience, ???) |c, g, e, i| {
  52. const role_name = switch (c) {
  53. .wizard => "Wizard",
  54. .thief => "Thief",
  55. .bard => "Bard",
  56. .warrior => "Warrior",
  57. };
  58. std.debug.print("{d}. {s} (Gold: {d}, XP: {d})\n", .{
  59. i,
  60. role_name,
  61. g,
  62. e,
  63. });
  64. }
  65. }
  66. //
  67. // By the way, storing our character data in arrays like this
  68. // isn't *just* a silly way to demonstrate multi-object 'for'
  69. // loops.
  70. //
  71. // It's *also* a silly way to introduce a concept called
  72. // "data-oriented design".
  73. //
  74. // Let's use a metaphor to build up an intuition for what this is
  75. // all about:
  76. //
  77. // Let's say you've been tasked with grabbing three glass
  78. // marbles, three spoons, and three feathers from a magic bag.
  79. // But you can't use your hands to grab them. Instead, you must
  80. // use a marble scoop, spoon magnet, and feather tongs to grab
  81. // each type of object.
  82. //
  83. // Now, would you rather use the magic bag:
  84. //
  85. // A. Grouped the items in clusters so you have to pick up one
  86. // marble, then one spoon, then one feather?
  87. //
  88. // OR
  89. //
  90. // B. Grouped the items by type so you can pick up all of the
  91. // marbles at once, then all the spoons, then all of the
  92. // feathers?
  93. //
  94. // If this metaphor is working, hopefully, it's clear that the 'B'
  95. // option would be much more efficient.
  96. //
  97. // Well, it probably comes as little surprise that storing and
  98. // using data in a sequential and uniform fashion is also more
  99. // efficient for modern CPUs.
  100. //
  101. // Decades of OOP practices have steered people towards grouping
  102. // different data types together into mixed-type "objects" with
  103. // the intent that these are easier on the human mind.
  104. // Data-oriented design groups data by type in a way that is
  105. // easier on the computer.
  106. //
  107. // With clever language design, maybe we can have both.
  108. //
  109. // In the Zig community, you may see the difference in groupings
  110. // presented with the terms "Array of Structs" (AoS) versus
  111. // "Struct of Arrays" (SoA).
  112. //
  113. // To envision these two designs in action, imagine an array of
  114. // RPG character structs, each containing three different data
  115. // types (AoS) versus a single RPG character struct containing
  116. // three arrays of one data type each, like those in the exercise
  117. // above (SoA).
  118. //
  119. // For a more practical application of "data-oriented design"
  120. // watch the following talk from Andrew Kelley, the creator of Zig:
  121. // https://vimeo.com/649009599
  122. //