You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Ability to specify a compile-time method ID expression for getters: PR [#922](https://github.com/tact-lang/tact/pull/922) and PR [#932](https://github.com/tact-lang/tact/pull/932)
18
-
- Destructuring of structs and messages: PR [#856](https://github.com/tact-lang/tact/pull/856), PR [#969](https://github.com/tact-lang/tact/pull/969)
18
+
- Destructuring of structs and messages: PR [#856](https://github.com/tact-lang/tact/pull/856), PR [#964](https://github.com/tact-lang/tact/pull/964), PR [#969](https://github.com/tact-lang/tact/pull/969)
19
19
- Docs: automatic links to Web IDE from all code blocks: PR [#994](https://github.com/tact-lang/tact/pull/994)
20
20
- The `SendDefaultMode` send mode constant to the standard library: PR [#1010](https://github.com/tact-lang/tact/pull/1010)
21
21
- Docs: initial semi-automated Chinese translation of the documentation: PR [#942](https://github.com/tact-lang/tact/pull/942)
The following statements can appear anywhere in the [function](/book/functions) body.
7
9
8
10
## `let` statement {#let}
@@ -96,6 +98,157 @@ value += 5; // augmented assignment (one of the many, see below)
96
98
97
99
:::
98
100
101
+
## Destructuring assignment
102
+
103
+
<Badgetext="Available since Tact 1.6"variant="tip"size="medium"/><p/>
104
+
105
+
The destructuring assignment is a concise way to unpack [Structs][s] and [Messages][m] into distinct variables. It mirrors the [instantiation syntax](/book/expressions#instantiation), but instead of creating a new [Struct][s] or [Message][m] it binds every field or some of the fields to their respective variables.
106
+
107
+
The syntax is derived from the [`let` statement](#let), and instead of specifying the variable name directly it involves specifying the structure type on the left side of the [assignment operator `={:tact}`](/book/operators#assignment), which corresponds to the structure type of the value on the right side.
108
+
109
+
```tact {6}
110
+
// Definition of Example
111
+
struct Example { number: Int }
112
+
113
+
// An arbitrary helper function
114
+
fun get42(): Example { return Example { number: 42 } }
115
+
116
+
fun basic() {
117
+
// Basic syntax of destructuring assignment (to the left of "="):
118
+
let Example { number } = get42();
119
+
// ------- ------ -------
120
+
// ↑ ↑ ↑
121
+
// | | gives the Example Struct
122
+
// | definition of "number" variable, derived
123
+
// | from the field "number" in Example Struct
124
+
// target structure type "Example"
125
+
// to destructure fields from
126
+
127
+
// Same as above, but with an instantiation
128
+
// to showcase how destructuring syntax mirrors it:
129
+
let Example { number } = Example { number: 42 };
130
+
// ----------------------
131
+
// ↑
132
+
// instantiation of Example Struct
133
+
134
+
// Above examples of syntax are roughly equivalent
135
+
// to the following series of statements:
136
+
let example = Example { number: 42 };
137
+
let number = example.number;
138
+
}
139
+
```
140
+
141
+
Just like in [instantiation](/book/expressions#instantiation), the trailing comma is allowed.
142
+
143
+
```tact
144
+
struct Example { number: Int }
145
+
146
+
fun trailblazing() {
147
+
let Example {
148
+
number, // trailing comma inside variable list
149
+
} = Example {
150
+
number: 42, // trailing comma inside field list
151
+
};
152
+
}
153
+
```
154
+
155
+
:::note
156
+
157
+
[Augmented assignment operators](/book/operators#augmented-assignment) do not make sense for such assignments and will therefore be reported as parsing errors:
158
+
159
+
```tact
160
+
struct Example { number: Int }
161
+
fun get42(): Example { return Example { number: 42 } }
162
+
163
+
fun basic() {
164
+
let Example { number } += get42();
165
+
// ^ this will result in the parse error:
166
+
// expected "="
167
+
}
168
+
```
169
+
170
+
:::
171
+
172
+
To create a binding under a different variable name, specify it after the semicolon `:{:tact}`.
173
+
174
+
```tact
175
+
// Similar definition, but this time field is called "field", not "number"
176
+
struct Example { field: Int }
177
+
178
+
fun naming(s: Example) {
179
+
let Example { field: varFromField } = s;
180
+
// ------------ ↑
181
+
// ↑ |
182
+
// | instance of Example Struct, received
183
+
// | as a parameter of the function "naming"
184
+
// definition of "varFromField" variable, derived
185
+
// from the field "field" in Example Struct
186
+
}
187
+
```
188
+
189
+
Note, that the order of bindings doesn't matter — all the fields retain their values and types under their names no matter the order in which they stand in their definition in the respective [Struct][s] or [Message][m].
190
+
191
+
```tact
192
+
// "first" goes first, then goes "second"
193
+
struct Two { first: Int; second: String }
194
+
195
+
fun order(s: Two) {
196
+
let Two { second, first } = s;
197
+
// ------ -----
198
+
// ↑ ↑
199
+
// | this variable will be of type Int,
200
+
// | same as the "first" field on Struct Two
201
+
// this variable will be of type String,
202
+
// same as the "second" field in Struct Two
203
+
}
204
+
```
205
+
206
+
Destructuring assignment is exhaustive and requires specifying all the fields as variables. To deliberately ignore some of the fields, use an underscore `_{:tact}`, which discards the considered field's value. Note, that such wildcard variable name `_{:tact}` cannot be accessed:
207
+
208
+
```tact
209
+
// "first" goes first, then goes "second"
210
+
struct Two { first: Int; second: String }
211
+
212
+
fun discard(s: Two) {
213
+
let Two { second: _, first } = s;
214
+
// ---
215
+
// ↑
216
+
// discards the "second" field, only taking the "first"
217
+
}
218
+
```
219
+
220
+
To completely ignore the rest of the fields, use `..` at the end of the list:
221
+
222
+
```tact
223
+
struct Many { one: Int; two: Int; three: Int; fans: Int }
224
+
225
+
fun ignore(s: Many) {
226
+
let Many { fans, .. } = s;
227
+
// --
228
+
// ↑
229
+
// ignores all the unspecified fields,
230
+
// defining only "fans"
231
+
}
232
+
```
233
+
234
+
:::caution
235
+
236
+
At the moment, destructuring of nested [Structs][s] or [Messages][m] isn't allowed. That is, the following won't work:
237
+
238
+
```tact
239
+
struct First { nested: Second }
240
+
struct Second { field: Int }
241
+
242
+
fun example() {
243
+
let prep = First { nested: Second { field: 42 } };
0 commit comments