复合类型 map<K, V>
用于将 K
类型的键与 V
类型的相应值关联起来。
例如,map<Int, Int>
的键和值使用 [英特
][英特] 类型:
允许的类型
允许的密钥类型
允许的值类型:
业务
声明,emptyMap()
作为局部变量,使用标准库的 emptyMap()
函数:
作为 持久状态变量:
请注意,类型为 map<K, V>
的 持久状态变量 默认为空,不需要默认值,也不需要在 init()
函数中进行初始化。
设置值,.set()
要设置或替换键下的值,请调用 .set()
方法,所有地图都可以使用该方法。
获取值,.get()
通过调用 .get()
方法,检查是否在地图中找到了键,所有地图都可以访问该方法。 如果键丢失,则返回 null
;如果键找到,则返回值。
删除条目,.del()
要删除单个键值对(单个条目),请使用 .del()
方法。 如果删除成功,则返回 true
,否则返回 false
。
要删除映射表中的所有条目,请使用 emptyMap()
函数重新分配映射表:
采用这种方法后,即使已将映射声明为持久状态变量,映射之前的所有条目也会从合约中完全删除。 因此,将地图分配给 emptyMap()
不会产生任何隐藏或突然的存储费用。
检查条目是否存在, .exists()
Available since Tact 1.5
映射上的 .exists()
方法,如果给定键下的值在映射中存在,则返回 true
,否则返回 false
。
检查是否为空,.isEmpty()
地图上的 .isEmpty()
方法 如果地图为空,则返回 true
,否则返回 false
:
转换为 Cell
, .asCell()
在地图上使用 .asCell()
方法,将其所有值转换为 [单元格
][单元格] 类型。 请注意,[Cell
][单元格] 类型最多只能存储 1023 位,因此将更大的映射转换为单元格会导致错误。
例如,这种方法适用于在回复正文中直接发送小地图:
遍历条目
要遍历地图条目,有一个 foreach
循环语句:
了解更多相关信息:foreach
loop in Book→Statements.
请注意,也可以将映射作为简单数组使用,只要定义一个 map<Int, V>
,键为 Int
类型,值为任何允许的 V
类型,并跟踪单独变量中的项数即可:
在此类地图上设置上限限制通常很有用,这样就不会[触及极限](#limits-and-drawbacks)。
序列化
可以对映射键、值或两者进行整数序列化,以保留空间并降低存储成本:
局限性和缺点
虽然地图在小范围内使用起来很方便,但如果项目数量不受限制,地图的大小会大幅增加,就会产生很多问题:
-
由于智能合约状态大小的上限约为 [Cell
][cell] 类型的 65,000 项,因此整个合约的映射存储上限约为 30,000 键值对。
-
地图中的条目越多,计算费 就越高。 因此,处理大型地图使得计算费用难以预测和管理。
-
在单个合同中使用大型地图无法分散工作量。 因此,与使用较小的地图和大量交互式智能合约相比,这可能会使整体性能大打折扣。
要解决此类问题,可以将地图上的上限限制设置为常数,并在每次为地图设置新值时对其进行检查:
如果您仍然需要大地图或无约束(无限大)地图,最好按照TON 区块链的异步和基于角色的模型来构建您的智能合约。 也就是说,使用合约分片,让整个区块链成为地图的一部分。