@@ -15,11 +15,12 @@ condition holds.
15
15
### Range
16
16
17
17
The ` range ` action performs an action for each entry in a slice or map; we say that range _ iterates_ over the slice or
18
- map. If you have worked with other programming languages, ` range ` is roughly equivalent to a for-each loop.
18
+ map. If you have experience with other programming languages, ` range ` is roughly equivalent to a for-each loop.
19
19
20
20
#### Ranging over slices
21
21
22
- Consider the following program, which iterates over a slice of snacks and generates a line of output for each one.
22
+ We will explain how ` range ` works with a slice using an illustrative example. The program below iterates over a slice of
23
+ snacks and generates a line of output for each one.
23
24
24
25
``` yag
25
26
{{ $snacks := cslice
@@ -32,8 +33,11 @@ Consider the following program, which iterates over a slice of snacks and genera
32
33
{{ end }}
33
34
```
34
35
35
- Within the range block, the dot ` . ` is set to successive elements of the slice. In the first iteration, for instance,
36
- ` . ` holds the first element of the slice: ` (sdict "Name" "chips" "Calories" 540) ` . Hence
36
+ The loop body—that is, the code between the opening ` range $snacks ` and the closing ` end ` —is executed
37
+ multiple times, with the dot ` . ` set to each element of the slice in succession.
38
+
39
+ For instance, in the first iteration, the ` . ` holds the first element of the slice:
40
+ ` (sdict "Name" "chips" "Calories" 540) ` . So
37
41
38
42
``` yag
39
43
{{ .Name }} contain {{ .Calories }} calories.
@@ -45,7 +49,8 @@ evaluates to
45
49
chips contain 540 calories.
46
50
```
47
51
48
- and likewise for the second and third elements. The complete output is
52
+ Likewise, the second iteration produces ` peanuts contain 580 calories ` , and the third produces ` crackers contain 500 calories. `
53
+ The complete output of the program is
49
54
50
55
``` txt
51
56
chips contain 540 calories.
@@ -55,9 +60,9 @@ chips contain 540 calories.
55
60
crackers contain 500 calories.
56
61
```
57
62
58
- This output contains some unwanted whitespace: ideally, we want each snack to appear on a separate line with no leading
59
- indentation. However, the extra whitespace is to be expected with our current program: the range block is indented, and
60
- YAGPDB is simply reproducing that indentation.
63
+ Notice that this output contains some unwanted whitespace: ideally, we want each snack to appear on a separate line with
64
+ no leading indentation. However, the extra whitespace is to be expected with our current program; the range block is
65
+ indented, and YAGPDB is simply reproducing that indentation:
61
66
62
67
``` yag
63
68
{{ range $snacks }}
@@ -66,37 +71,46 @@ YAGPDB is simply reproducing that indentation.
66
71
{{ end }}
67
72
```
68
73
69
- One solution, then, is to remove the whitespace in our source code, save the final newline:
74
+ To fix the excess whitespace in the output, then, one solution is to remove the corresponding whitespace in our source
75
+ code:
70
76
71
77
``` yag
72
- {{ range $snacks }}{{ .Name }} contains {{ .Calories }} calories
78
+ {{ range $snacks }}{{ .Name }} contains {{ .Calories }} calories.
73
79
{{ end }}
74
80
```
75
81
76
- Although this version works, we have sacrificed readability in the process. To retain the indentation in our source code
77
- while simultaneously avoiding unwanted whitespace in our output, we can use _ trim markers_ .
82
+ However, though this version works, we have sacrificed readability in the process. Can we find a way to keep our source
83
+ code indented while simultaneously hiding this indentation from the final output? It turns out that we can, by carefully
84
+ adding _ trim markers_ .
78
85
79
86
``` yag
80
87
{{ range $snacks }}
81
88
{{- .Name }} contain {{ .Calories }} calories.
89
+ ^^^
82
90
{{ end }}
83
91
```
84
92
85
93
` {{- ` is a _ left trim marker_ that instructs YAGPDB to ignore all leading whitespace, so this new version is
86
- functionally equivalent to the previous solution. A right trim marker , ` -}} ` , also exists and trims all trailing
87
- whitespace.
94
+ functionally equivalent to the previous solution. A corresponding _ right trim marker _ , ` -}} ` , also exists and trims all
95
+ trailing whitespace.
88
96
89
97
{{< callout context="tip" title="Tip: Trim Markers" icon="outline/rocket" >}}
90
98
91
- Use trim markers ` {{- ` and ` -}} ` to remove unwanted whitespace in output while keeping your source code readable.
99
+ Use trim markers ` {{- ` and ` -}} ` to control the whitespace output by your program.
100
+
101
+ A mnemonic to help remember what ` {{- ` and ` -}} ` do is to view them as arrows that gobble up whitespace in the direction
102
+ they point; for instance, ` {{- ` points left, and eats all whitespace to the left.
92
103
93
104
{{< /callout >}}
94
105
95
106
#### Ranging over maps
96
107
97
108
It is also possible to range over the (key, value) pairs of a map. To do so, assign two variables to the result of the
98
- range action, corresponding to the key and value respectively. For example, the following program outputs the prices of
99
- various types of fruit, formatted nicely to 2 decimal places with the ` printf ` function.
109
+ range action, corresponding to the key and value respectively. (Note that the dot ` . ` is still overwritten when ranging
110
+ with variables.)
111
+
112
+ For example, the following program displays the prices of various types of fruit, formatted nicely to 2 decimal places
113
+ with the ` printf ` function.
100
114
101
115
``` yag
102
116
{{ $fruitPrices := sdict "pineapple" 3.50 "apple" 1.50 "banana" 2.60 }}
@@ -106,19 +120,19 @@ various types of fruit, formatted nicely to 2 decimal places with the `printf` f
106
120
{{ end }}
107
121
```
108
122
109
- Note that the names of the variables assigned to the key and value are arbitrary; instead of
110
- ` range $fruit, $price := $fruitPrices ` , we could also have written ` range $k, $v := $fruitPrices ` . However,
111
- if we use the names ` $k ` , ` $v ` , we must consistently refer to those in the loop body. That is, the following program
112
- is erroneous:
123
+ The names of the variables assigned to the key and value are arbitrary; instead of
124
+ ` range $fruit, $price := $fruitPrices ` , we could also have written ` range $k, $v := $fruitPrices ` .
125
+ However, if we use the names ` $k ` , ` $v ` , we must consistently refer to those in the loop body. That is, the following
126
+ program is erroneous:
113
127
114
128
``` yag
115
129
{{ range $k, $v := $fruitPrices }}
116
- {{- /* ERROR: undefined variables $fruit, $price */}}
130
+ {{- /* ERROR: $fruit and $price are undefined; must use $k and $v instead */}}
117
131
{{- $fruit }} costs ${{ printf "%.02f" $price }}.
118
132
{{ end }}
119
133
```
120
134
121
- {{< callout context="tip " title="Tip " icon="outline/rocket " >}}
135
+ {{< callout context="note " title="Note " icon="outline/info-circle " >}}
122
136
123
137
The two-variable form of range can also be used with a slice, in which case the first variable tracks the position of
124
138
the element starting from ` 0 ` .
@@ -162,11 +176,11 @@ There are a few other, less common ways to invoke the range action.
162
176
executed if the slice or map is empty.
163
177
164
178
``` yag
165
- {{ $empty := cslice }}
166
- {{ range $empty }}
167
- {{/* ... */}}
179
+ {{ $users := cslice }} {{/* imagine this data is dynamically generated */ }}
180
+ {{ range $user := $users }}
181
+ {{/* do something with $user */}}
168
182
{{ else }}
169
- slice was empty
183
+ no users
170
184
{{ end }}
171
185
```
172
186
0 commit comments