存储映射
另一个重要的公共集合是存储图。
标准库中的类型 StorageMap<K, V>”使用哈希函数存储类型为 K 的键到类型为 V 的值的映射,该函数决定如何将这些键和值放入 _存储槽_中。这类似于 Rust的HashMap<K, V> 但有一些区别。
当您不想使用索引(如使用向量)而是使用任意类型的键来查找数据时,存储映射非常有用。例如,在构建基于账本的子货币智能合约时,您可以在存储映射中跟踪每个钱包的余额,其中每个键都是钱包的,Address值是每个钱包的余额。给定一个Address,您可以检索其余额。 与 类似StorageVec<T>, StorageMap<K, V> 只能在合约中使用,因为只有合约才被允许访问持久存储。
StorageMap<T> 包含在 标准库前奏 中,这意味着无需手动导入它。
创建新的空存储映射
要创建一个新的空存储映射,我们必须在一个storage块中声明该映射,如下所示:
map: StorageMap<Address, u64> = StorageMap::<Address, u64> {},就像任何其他存储变量一样,声明时需要两个东西StorageMap:类型注释和初始化器。初始化器只是一个空类型的结构体,StorageMap因为StorageMap<K, V>它本身就是一个空结构体!所有有趣的东西都StorageMap<K, V>在其方法中实现。
存储映射,就像 Vec<T> 和 StorageVec<T>, 一样,是使用泛型实现的,这意味着标准库提供的 StorageMap<K, V> 类型可以将任何类型 K 的键映射到任何类型 V的值。在上面的例子中,我们告诉Sway编译器map中的 StorageMap<K, V> 将把 Address类型的键映射到 u64类型的值。
更新存储映射
要将键值对插入存储映射,我们可以使用此insert方法。
例如:
#[storage(write)]
fn insert_into_storage_map() {
let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);
storage.map.insert(addr1, 42);
storage.map.insert(addr2, 77);
}这里要注意两个细节。首先,为了使用 insert, 我们需要先使用关键字访问存储映射 storage 。其次,由于 insert 需要 写入 存储,因此 #[storage(write)] 需要在调用 的 ABI 函数上进行注释 insert。
注意 对于合同中定义的任何尝试插入到映射中的私有函数,也需要存储注释。
注意
mut声明时 无需添加关键字StorageMap<K, V>。所有存储变量默认都是可变的。
访问存储映射中的值
key我们可以通过将其提供给方法从存储图中获取一个值get。
例如:
#[storage(read, write)]
fn get_from_storage_map() {
let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);
storage.map.insert(addr1, 42);
storage.map.insert(addr2, 77);
let value1 = storage.map.get(addr1).try_read().unwrap_or(0);
}这里, value1 w将具有与第一个地址相关联的值,结果将是 42。 get '方法返回一个 Option<V>; 如果那个键在存储映射中没有值, get将返回 None。这个程序通过调用 unwrap_or来处理Option ,如果 map没有键的条目,则将value1设置为零。
具有多个键的映射
可以使用元组作为键来实现具有多个键的映射。例如:
map_two_keys: StorageMap<(b256, bool), b256> = StorageMap::<(b256, bool), b256> {},嵌套存储映射
可以按如下方式嵌套存储映射:
nested_map: StorageMap<u64, StorageMap<u64, u64>> = StorageMap::<u64, StorageMap<u64, u64>> {},然后可以按如下方式访问嵌套映射:
#[storage(read, write)]
fn access_nested_map() {
storage.nested_map.get(0).insert(1, 42);
storage.nested_map.get(2).insert(3, 24);
assert(storage.nested_map.get(0).get(1).read() == 42);
assert(storage.nested_map.get(0).get(0).try_read().is_none()); // Nothing inserted here
assert(storage.nested_map.get(2).get(3).read() == 24);
assert(storage.nested_map.get(2).get(2).try_read().is_none()); // Nothing inserted here
}