Icon Link存储映射

另一个重要的常见集合是存储映射。

标准库中的类型 StorageMap<K, V> 存储了键类型为 K,值类型为 V 的映射,使用哈希函数确定如何将这些键和值放入 存储槽 中。这类似于Rust 的 HashMap<K, V> Icon Link,但有一些区别。

当您想要通过键查找数据时,存储映射非常有用,而不是像使用向量那样通过索引。例如,当构建基于账本的子货币智能合约时,您可以在存储映射中跟踪每个钱包的余额,其中每个键都是钱包的 Address,而值是每个钱包的余额。给定一个 Address,您可以检索其余额。

StorageVec<T> 类似,StorageMap<K, V> 只能在合约中使用,因为只有合约可以访问持久存储。

StorageMap<T> 包含在标准库预导入 中,这意味着不需要手动导入它。

Icon Link创建新的存储映射

要创建一个新的空存储映射,我们必须在 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 的值。

Icon Link更新存储映射

要将键值对插入存储映射,我们可以使用 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 需要 写入 存储,所以调用 insert 的 ABI 函数需要添加 #[storage(write)] 注解。

Icon InfoCircle

注意 对于尝试插入映射的任何私有函数,都需要在合约中添加存储注解。

Icon InfoCircle

注意 声明 StorageMap<K, V> 时无需添加 mut 关键字。所有存储变量默认都是可变的。

Icon Link访问存储映射中的值

我们可以通过将其 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 将具有与第一个地址关联的值,结果将为 42get 方法返回一个 Option<V>;如果存储映射中没有该键的值,get 将返回 None。此程序通过调用 unwrap_or 处理 Option,如果 map 没有键的条目,则将 value1 设置为零。

Icon Link具有多个键的存储映射

可以使用元组作为键实现具有多个键的映射。例如:

map_two_keys: StorageMap<(b256, bool), b256> = StorageMap::<(b256, bool), b256> {},

Icon Link嵌套存储映射

可以按以下方式嵌套存储映射:

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
}