Maps are a dictionary type that can hold an arbitrary number of items, each under a different key.
The keys in maps can either be an Int
type or an Address
type.
You can check if a key is found in the map by calling the get()
method. This will return null
if the key is missing or the value if the key is found. Replace the value under a key by calling the set()
method.
Integers in maps stored in state currently use the largest integer size (257-bit). Future versions of Tact will let you optimize the encoding size.
Maps are designed to hold a limited number of items. Only use a map if you know the upper bound of items that it may hold. It's also a good idea to write a test to add the maximum number of elements to the map and see how gas behaves under stress.
If the number of items is unbounded and can potentially grow to billions, you'll need to architect your contract differently. We will discuss unbounded maps later on under the topic of contract sharding.
All Examplesimport "@stdlib/deploy"; struct StrctOpts { sa: Int?; sb: Bool?; sc: Address?; } message MsgOpts { ma: Int?; mb: Bool?; mc: Address?; md: StrctOpts?; } contract Optionals with Deployable { ca: Int?; cb: Bool?; cc: Address?; cd: StrctOpts?; init(a: Int?, b: Bool?, c: Address?) { self.ca = a; self.cb = b; self.cc = c; self.cd = StrctOpts{sa: null, sb: true, sc: null}; } receive(msg: MsgOpts) { let i: Int = 12; if (msg.ma != null) { i = i + msg.ma!!; // !! tells the compiler this can't be null self.ca = i; } } get fun optInt(): Int? { return self.ca; } get fun optIntVal(): Int { if (self.ca == null) { return -1; } else { return self.ca!!; // !! tells the compiler this can't be null } } get fun optNested(): Int? { if (self.cd != null && (self.cd!!).sa != null) { return (self.cd!!).sa!!; // !! tells the compiler this can't be null } else { return null; } } }