Skip to content
This repository was archived by the owner on Dec 12, 2024. It is now read-only.

Commit 6930944

Browse files
authored
feat: foreach statement (#220)
1 parent 74de045 commit 6930944

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

pages/book/maps.mdx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,25 @@ contract Example {
181181

182182
### Traverse over entries [#traverse]
183183

184-
At the moment Tact doesn't have a special syntax for iterating over maps. However, it's possible to use maps as a simple arrays if you define a `map<Int, v>{:tact}` with an [`Int{:tact}`][int] type for the keys and keep track of the number of items in the separate variable:
184+
To iterate over map entries there is a [`foreach{:tact}`](/book/statements#foreach-loop) loop statement:
185+
186+
```tact
187+
// Empty map
188+
let fizz: map<Int, Int> = emptyMap();
189+
190+
// Setting a couple of values under different keys
191+
fizz.set(42, 321);
192+
fizz.set(7, 123);
193+
194+
// Iterating over in a sequential order: from the smallest keys to the biggest ones
195+
foreach (key, value in fizz) {
196+
dump(key); // will dump 7 on the first iteration, then 42 on the second
197+
}
198+
```
199+
200+
Read more about it: [`foreach{:tact}` loop in Book→Statements](/book/statements#foreach-loop).
201+
202+
Note, that it's also possible to use maps as simple arrays if you define a `map<Int, V>{:tact}` with an [`Int{:tact}`][int] type for the keys, any allowed `V` type for values and keep track of the number of items in the separate variable:
185203

186204
```tact
187205
contract Iteration {

pages/book/statements.mdx

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ repeat (10) { // repeat exactly 10 times
149149

150150
### `while` [#while-loop]
151151

152-
While loop continues executing the block of code as long as the given condition is `true{:tact}`.
152+
The `while{:tact}` loop continues executing the block of code as long as the given condition is `true{:tact}`.
153153

154154
In the following example, the value of `x` is decremented by $1$ on each iteration, so the loop will run $10$ times:
155155

@@ -173,8 +173,52 @@ do {
173173
} until (x <= 0);
174174
```
175175

176+
### `foreach` [#foreach-loop]
177+
178+
The `foreach{:tact}` loop operates on key-value pairs (entries) of [`map<K, V>{:tact}`](/book/maps) type in sequential order: from the smallest keys of the map to the biggest ones.
179+
180+
This loop executes a block of code for each entry in the given map, capturing the key and value on each iteration. This is handy when you don't know in advance how many items there is in the map or don't want to explicitly look for each of the entry using [`.set(){:tact}`](/book/maps#set) [method](/book/functions#extension-function) of maps.
181+
182+
Note, that the names of captured key and value pair on each iteration are arbitrary and can be any valid Tact identifier, provided that they're new to the current scope. The most common options are: `k` and `v`, or `key` and `value`.
183+
184+
In the following example, map `cells` has $4$ entries, so the loop will run $4$ times:
185+
186+
```tact
187+
// Empty map
188+
let cells: map<Int, Cell> = emptyMap();
189+
190+
// Setting four values
191+
cells.set(1, beginCell().storeUint(100, 16).endCell());
192+
cells.set(2, beginCell().storeUint(200, 16).endCell());
193+
cells.set(3, beginCell().storeUint(300, 16).endCell());
194+
cells.set(4, beginCell().storeUint(400, 16).endCell());
195+
196+
// A variable for summing up the values
197+
let sum: Int = 0;
198+
199+
// For each key and value pair in cells map, do:
200+
foreach (key, value in cells) { // or just k, v
201+
let s: Slice = value.beginParse(); // convert Cell to Slice
202+
sum += s.loadUint(16); // sum the Slice values
203+
}
204+
dump(sum); // 1000
205+
```
206+
207+
<Callout type="warning" emoji="⚠️">
208+
209+
Note, that at the moment `foreach{:tact}` works only with explicitly provided map identifiers. That is, returning a map from a function and trying to iterate over its entries won't work:
210+
211+
```tact
212+
foreach (k, v in emptyMap()) {
213+
// ^ this will give a rather cryptic error message:
214+
// Syntax error: expected ")"
215+
}
216+
```
217+
218+
</Callout>
219+
176220
<Callout>
177221

178-
For more loop examples see: [Loops in Tact-By-Example](https://tact-by-example.org/04-loops).
222+
For additional loop examples see: [Loops in Tact-By-Example](https://tact-by-example.org/04-loops).
179223

180224
</Callout>

0 commit comments

Comments
 (0)