diff --git a/dev-docs/CHANGELOG.md b/dev-docs/CHANGELOG.md index 9ef5ade75..3c0ed84db 100644 --- a/dev-docs/CHANGELOG.md +++ b/dev-docs/CHANGELOG.md @@ -103,6 +103,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Documented `BaseTrait` and methods in stdlib code: PR [#1296](https://github.com/tact-lang/tact/pull/1296) - Document how storage variables get updated in relation to the `init()` function: PR [#1311](https://github.com/tact-lang/tact/pull/1311) - Document compiler upgrades in Blueprint and other Tact projects: PR [#1560](https://github.com/tact-lang/tact/pull/1560) +- Illustrate how nested maps can be created: PR [#1593](https://github.com/tact-lang/tact/pull/1593) ### Release contributors diff --git a/docs/src/content/docs/book/maps.mdx b/docs/src/content/docs/book/maps.mdx index 6d9a07007..ea9565b71 100644 --- a/docs/src/content/docs/book/maps.mdx +++ b/docs/src/content/docs/book/maps.mdx @@ -15,6 +15,38 @@ struct IntToInt { } ``` +Since maps can use any given [Struct][struct] as their [value types](#allowed-types), the nested maps can be created via helper structures like this: + +```tact +import "@stdlib/deploy"; + +// A `map
` packed into the `AllowanceMap` structure +struct AllowanceMap { unbox: map } + +contract NestedMaps with Deployable { + get fun test(): Int { + // An outer map `map`, + // with `AllowanceMap` Structs as values, + // each containing maps of type `map` + let allowances: map = emptyMap(); + + // An inner map in the `unbox` field of the `AllowanceMap` Struct + let allowance = AllowanceMap{ unbox: emptyMap() }; + + // Setting the inner map entry + allowance.unbox.set(myAddress(), 42); + + // Setting the outer map entry + allowances.set(myAddress(), allowance); + + // Produces 42 + return allowances.get(myAddress())!!.unbox.get(myAddress())!!; + } +} +``` + +Keep in mind that on [TVM][tvm], maps are represented as [`Cell{:tact}`][cell] type, which is very gas-intensive. Also, nested maps will reach the [limits](#limits-and-drawbacks) faster than regular maps. + ## Allowed types Allowed key types: @@ -28,7 +60,7 @@ Allowed value types: * [`Bool{:tact}`](/book/types#booleans) * [`Cell{:tact}`][cell] * [`Address{:tact}`][p] -* [Struct](/book/structs-and-messages#structs) +* [Struct][struct] * [Message](/book/structs-and-messages#messages) ## Serialization @@ -486,7 +518,7 @@ It's often useful to set an upper-bound restriction on such maps, so that you [d :::caution - Note, that manually keeping track of number of items or checking the length of such map is very error-prone and generally discouraged. Instead, try to wrap your map into the [Struct](/book/structs-and-messages#structs) and define [extension functions](/book/functions#extension-function) on it. See example in the Cookbook: [How to emulate an array using a map wrapped in a Struct](/cookbook/data-structures#array). + Note, that manually keeping track of number of items or checking the length of such map is very error-prone and generally discouraged. Instead, try to wrap your map into the [Struct][struct] and define [extension functions](/book/functions#extension-function) on it. See example in the Cookbook: [How to emulate an array using a map wrapped in a Struct](/cookbook/data-structures#array). ::: @@ -543,6 +575,7 @@ If you still need a large map or an unbound (infinitely large) map, it's better [p]: /book/types#primitive-types [int]: /book/integers [cell]: /book/cells#cells +[struct]: /book/structs-and-messages#structs [hashmap]: https://docs.ton.org/develop/data-formats/tl-b-types#hashmap [tvm]: https://docs.ton.org/learn/tvm-instructions/tvm-overview