|
| 1 | +# Iterate once |
| 2 | + |
| 3 | +```rust |
| 4 | +const SIGNS: [&'static str; 4] = ["wink", "double blink", "close your eyes", "jump"]; |
| 5 | +const REVERSE_SIGNS: u8 = 16; |
| 6 | + |
| 7 | +pub fn actions(n: u8) -> Vec<&'static str> { |
| 8 | + let (mut action, action_incr, end) = match n & REVERSE_SIGNS { |
| 9 | + 0 => (0, 1, 4), |
| 10 | + _ => (3, -1, -1), |
| 11 | + }; |
| 12 | + let mut output: Vec<&'static str> = Vec::new(); |
| 13 | + |
| 14 | + loop { |
| 15 | + if action == end { |
| 16 | + break; |
| 17 | + } |
| 18 | + if (n & (1 << action)) != 0 { |
| 19 | + output.push(SIGNS[action as usize]) |
| 20 | + } |
| 21 | + action += action_incr |
| 22 | + } |
| 23 | + output |
| 24 | +} |
| 25 | +``` |
| 26 | + |
| 27 | +This approach starts by defining a fixed-size [array][array] to hold the signal values in normal order. |
| 28 | + |
| 29 | +The `[&'static str; 4]` is used to give the type and length of the array. |
| 30 | +To be a [`const`][const], the size of the array must be known at compile time, so setting the type and length must be done explicitly, |
| 31 | +so the size in bytes of the fixed array can be deduced by the compiler from that and not by inspecting the element types and counting |
| 32 | +the elements itself. |
| 33 | + |
| 34 | +The value of `16` is defined as a `const` with a meaningful name so it won't be used as a [magic number][magic-number]. |
| 35 | + |
| 36 | +The `actions` function uses multiple assignment with a `match` expression to define the variables that control iterating through the signals array, |
| 37 | +setting their values to iterate in either the normal or reverse order. |
| 38 | + |
| 39 | +The [bitwise AND operator][bitand] is used to check if the input number contains the signal for reversing the order of the other signals. |
| 40 | + |
| 41 | +For example, if the number passed in is `19`, which is `10011` in binary, then it is ANDed with `16`, which is `10000` in binary. |
| 42 | +The `1` in `10000` is also at the same position in `10011`, so the two values ANDed will not be `0`. |
| 43 | +- `10011` AND |
| 44 | +- `10000` = |
| 45 | +- `10000` |
| 46 | + |
| 47 | +If the number passed in is `3`, which is `00011` in binary, then it is ANDed with `16`, which is `10000` in binary. |
| 48 | +The `1` in `10000` is not at the same position in `00011`, so the two values ANDed will be `0`. |
| 49 | +- `00011` AND |
| 50 | +- `10000` = |
| 51 | +- `00000` |
| 52 | + |
| 53 | +If the number passed in does not contain the signal for reverse, then the iteration variables are set to iterate through the array of signals |
| 54 | +in their normal order, otherwise they are set to iterate through the arrray backwards.. |
| 55 | + |
| 56 | +The output `vector` is defined, and then the [`loop`][loop] begins. |
| 57 | + |
| 58 | +Normal iteration will start at index `0`. |
| 59 | +Reverse iteration will start at index `3`. |
| 60 | + |
| 61 | +Normal iteration will terminate when the index equals `4`. |
| 62 | +Reverse iteration will terminate when the index equals `-1`. |
| 63 | + |
| 64 | +Normal iteration will increase the index by `1` for each iteration. |
| 65 | +Reverse iteration will decrease the index by `1` for each iteration. |
| 66 | + |
| 67 | +For each iteration of the `loop`, the AND operator is used to check if the number passed in contains `1` [shifted left][shl] (`<<`) for the number of positions |
| 68 | +as the value being iterated. |
| 69 | + |
| 70 | +```rust |
| 71 | +if (n & (1 << action)) != 0 { |
| 72 | + output.push(SIGNS[action as usize]) |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +For example, if the number being iterated is `0`, then `1` is shifted left `0` times (so not shifted at all), and the number passed in is ANDed with `00001`. |
| 77 | +If the number passed in is `3`, which is `00011` in binary, then it is ANDed with `00001`. |
| 78 | +`00011` ANDed with `00001` is not equal to `0`, so the signal at the index of the array of signals is added to the output `vector`. |
| 79 | +The index used is the number being iterated, which is `0`, so the element at index `0` (`"wink"`) would be added to the output `vector` |
| 80 | +using the [push][push] function. |
| 81 | + |
| 82 | +If the number being iterated is `1`, then `1` is shifted left `1` time, and the number passed in is ANDed with `00010`. |
| 83 | +If the number passed in is `3`, which is `00011` in binary, then it is ANDed with `00010`. |
| 84 | +`00011` ANDed with `00010` is not equal to `0`, so the signal at the index of the array of signals is added to the output `vector`. |
| 85 | +The index used is the number being iterated, which is `1`, so the element at index `1` (`"double blink"`) would be added to the output `vector`. |
| 86 | + |
| 87 | +If the number passed in ANDed with the number being iterated is equal to `0`, then the signal in the array for that index is not added to the output `vector`. |
| 88 | + |
| 89 | +After iterating through the array of signals is done, the output `vector` is returned from the function. |
| 90 | + |
| 91 | +[array]: https://doc.rust-lang.org/std/primitive.array.html |
| 92 | +[const]: https://doc.rust-lang.org/std/keyword.const.html |
| 93 | +[magic-number]: https://en.wikipedia.org/wiki/Magic_number_(programming) |
| 94 | +[bitand]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html |
| 95 | +[shl]: https://doc.rust-lang.org/std/ops/trait.Shl.html |
| 96 | +[loop]: https://doc.rust-lang.org/rust-by-example/flow_control/loop.html |
| 97 | +[push]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push |
0 commit comments