You need to enable JavaScript to run this app. ink!中使用双AccountId为键Vec<u128>为值的HashMap存储报PackedLayout未实现错误
优惠活动
大模型
产品
解决方案
定价
更多

ink!中使用双AccountId为键Vec<u128>为值的HashMap存储报PackedLayout未实现错误

问题原因

ink! 存储中ink_storage::collections::Vec(存储型Vec)实现的是SpreadLayout trait,而ink_storage::collections::HashMap的Value要求必须实现PackedLayout trait,两者不匹配触发该报错。存储型Vec是分散存储在链上存储槽的,不能被打包成连续块作为HashMap的值存储。

解决方案

方案1:替换为普通Vec(推荐,适用于数据量较小的场景)

把HashMap的Value类型换成ink! 标准库提供的普通Vec(来自ink_prelude),普通Vec实现了PackedLayout,可以直接作为HashMap的值使用。
修改后的存储代码如下:

// 首先导入依赖
use ink_prelude::vec::Vec;

#[ink(storage)]
pub struct Item {
    shipment: ink_storage::collections::HashMap<
        (AccountId, AccountId),
        Vec<u128>,
    >,
}

初始化代码无需修改:

#[ink(constructor)]
pub fn new() -> Self {
    Self {
        shipment: ink_storage::collections::HashMap::new(),
    }
}

注意:该方案适合单个Vec的元素数量不超过数千的场景,如果元素过多会导致单次读写的gas费过高,甚至超出区块gas限制

方案2:使用Mapping适配大容量存储场景(适用于数据量大的场景)

如果你需要存储的Vec元素数量很大,更推荐用ink! 官方推荐的Mapping类型替代HashMap,通过嵌套索引的方式模拟存储型Vec的效果,读写单个元素的gas费稳定,不会随元素数量增长:

use ink_storage::Mapping;

#[ink(storage)]
pub struct Item {
    // 存储账户对对应Vec的总长度
    shipment_len: Mapping<(AccountId, AccountId), u32>,
    // 通过 账户对+索引 存具体的u128值
    shipment_items: Mapping<(AccountId, AccountId, u32), u128>,
}

初始化代码:

#[ink(constructor)]
pub fn new() -> Self {
    Self {
        shipment_len: Mapping::default(),
        shipment_items: Mapping::default(),
    }
}

后续可自行封装push、get、len等方法实现Vec的常用操作即可。

补充:如果是ink! 4.x及以上版本,官方已经弃用ink_storage::collections::HashMap,统一使用Mapping即可,性能更好也不存在上述trait适配问题

内容的提问来源于stack exchange,提问作者user15205786

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 00:36:03