如何从嵌套资源中获取值而非UUID?能否更新值?
问题描述
现有合约代码
pub resource interface InventoryPublic{ pub var items: @{UInt64: Grocery} } pub resource Inventory: InventoryPublic{ pub var items: @{UInt64: Grocery} pub fun addItem(item: @Grocery) { var olditem <- self.items[item.uuid] <- item //self.items[item.uuid] <-! item destroy olditem } init(){ self.items <- {} } destroy(){ destroy self.items } } pub fun createInventory(): @Inventory{ return <- create Inventory() } pub fun addItems(name: String, nos: Int, price: UFix64): @Grocery{ return <- create Grocery(_grocery: name,_units : nos, _price: price) }
当前查询脚本
import AgroLink from 0xf8d6e0586b0a20c7 pub fun main(acct: Address){ let myitems = getAccount(acct).getCapability(/public/InventoryPublic) .borrow<&AgroLink.Inventory>() ?? panic("Can't get public link!") log(myitems.items.keys) }
疑问
- 如何从嵌套资源中获取UUID对应的具体值而非仅键?
- 如果能获取值,是否可以对其进行更新?若可以,具体实现方法是什么?
解决方案
一、获取UUID对应的具体值
核心逻辑
当前脚本仅能拿到键,是因为直接访问了字典的keys属性。要获取对应值,需满足两个前提:
Grocery的字段(如name/units/price)需设为公开可访问(假设Grocery已定义这些字段);- 通过遍历字典键值对,或指定UUID直接取值。
实现脚本
方式1:遍历所有键值对
import AgroLink from 0xf8d6e0586b0a20c7 pub fun main(acct: Address){ let inventory = getAccount(acct).getCapability(/public/InventoryPublic) .borrow<&AgroLink.Inventory>() ?? panic("无法获取公开库存能力!") // 遍历所有UUID与对应商品信息 for uuid, item in inventory.items { log("UUID: \(uuid), 商品名: \(item.name), 数量: \(item.units), 价格: \(item.price)") } }
方式2:指定UUID直接取值
import AgroLink from 0xf8d6e0586b0a20c7 pub fun main(acct: Address, targetUUID: UInt64){ let inventory = getAccount(acct).getCapability(/public/InventoryPublic) .borrow<&AgroLink.Inventory>() ?? panic("无法获取公开库存能力!") if let item = inventory.items[targetUUID] { log("找到商品: 名称\(item.name), 数量\(item.units), 价格\(item.price)") } else { log("未找到UUID为\(targetUUID)的商品") } }
二、更新商品值的实现方法
限制说明
Cadence不允许外部直接修改合约内的资源/字典值,必须通过合约内部暴露的函数操作。需先修改合约添加更新逻辑,再编写脚本调用。
具体步骤
1. 修改合约:添加更新函数
在InventoryPublic接口中声明更新函数,再在Inventory资源中实现:
pub resource interface InventoryPublic{ pub var items: @{UInt64: Grocery} // 新增:声明更新商品的函数 pub fun updateItem(uuid: UInt64, newUnits: Int, newPrice: UFix64) } pub resource Inventory: InventoryPublic{ pub var items: @{UInt64: Grocery} pub fun addItem(item: @Grocery) { var olditem <- self.items[item.uuid] <- item destroy olditem } // 新增:实现更新逻辑 pub fun updateItem(uuid: UInt64, newUnits: Int, newPrice: UFix64) { // 取出商品资源,修改后放回字典 var item <- self.items[uuid] ?? panic("未找到对应UUID的商品") item.units = newUnits item.price = newPrice self.items[uuid] <- item } init(){ self.items <- {} } destroy(){ destroy self.items } } // 其余代码保持不变
若
Grocery是结构体而非资源,可简化为直接借读修改(无需资源转移操作)。
2. 编写调用更新的脚本
import AgroLink from 0xf8d6e0586b0a20c7 pub fun main(acct: Address, targetUUID: UInt64, newUnits: Int, newPrice: UFix64){ let inventory = getAccount(acct).getCapability(/public/InventoryPublic) .borrow<&AgroLink.Inventory>() ?? panic("无法获取公开库存能力!") inventory.updateItem(uuid: targetUUID, newUnits: newUnits, newPrice: newPrice) log("商品已更新") }
额外注意事项
- 确保
Grocery的字段为pub var(需修改)或pub let(只读),否则外部无法访问; - 原合约
addItem函数写法正确,若无需保留旧资源,可改用self.items[item.uuid] <-! item(强制替换并自动销毁旧值)简化代码。
内容的提问来源于stack exchange,提问作者Allen Chrisso Dhas
相关产品推荐
相关产品推荐

