【Substrate Collectables教程】【第1章基礎】4. 儲存 Storage Mapping
Storage Mapping
之前的 runtime 只允許為區塊鏈中的所有使用者儲存單個值。讓我們更多地思考下我們的鏈,顯然為每個使用者儲存其各自的值也是有用的(Storage Mapping)。
為此,我們將使用 storage mapping 替換簡單的 storage value
4.1 Substrate 特定型別
在我們進入 storage mappings 部分前,讓我們來談談我們將要使用的一些 substrate 特定型別。
預設的 runtime 模板包含一組 modules,這些 modules 暴露出了你開發區塊鏈需要涉及的型別。在你開發了更多 module 後,你甚至會自己構造新型別並暴露給 runtime 的其他部分。
在本教程中,我們將僅使用 3 種 substrate 特定型別:
- AccountId
- Balance
- Hash
我們的 module 本身不能訪問這些型別,但我們可以通過讓 module 的 Trait
繼承定義了這些型別的 module 來輕鬆獲取訪問許可權。在當前情況下,balances
module 有我們需要的一切東西:
pub trait Trait: balances::Trait {}
注意: 只能宣告一個Trait
像我們在上面的示例中所做的那樣,我們可以在指定了泛型 <T: Trait>
的任何地方通過使用 T::Type
來訪問這些型別。
4.2 宣告一個 Storage Map
Storage Map 允許你將基礎的 (key, value) 放入 runtime 儲存中。它可以像這樣宣告:
decl_storage! { trait Store for Module<T: Trait> as Example { SomeValue get(some_value_getter): map u32 => u32; MyValue: map T::AccountId => u32; } }
你可以看到,當你想要表示 "owned" 資料時,mapping 是非常有用的。由於我們可以建立從某個使用者(AccountId)到某些值(例如 MyValue)的 mapping,因此我們可以保留有關該使用者的儲存資訊。我們甚至可以在 runtime 中構建邏輯,使 runtime 可以管理具體有哪些使用者能修改那些值,這是我們將在本教程中使用的常見模式。
要使用 storage map,你需要匯入 support::StorageMap
。
4.3 使用 StorageMap
用於訪問 StorageMap
的函式與 StorageValue
的位於 同一位置:
/// Get the prefix key in storage. fn prefix() -> &'static [u8]; /// Get the storage key used to fetch a value corresponding to a specific key. fn key_for(x: &K) -> Vec<u8>; /// true if the value is defined in storage. fn exists<S: Storage>(key: &K, storage: &S) -> bool { storage.exists(&Self::key_for(key)[..]) } /// Load the value associated with the given key from the map. fn get<S: Storage>(key: &K, storage: &S) -> Self::Query; /// Take the value under a key. fn take<S: Storage>(key: &K, storage: &S) -> Self::Query; /// Store a value to be associated with the given key from the map. fn insert<S: Storage>(key: &K, val: &V, storage: &S) { storage.put(&Self::key_for(key)[..], val); } /// Remove the value under a key. fn remove<S: Storage>(key: &K, storage: &S) { storage.kill(&Self::key_for(key)[..]); } /// Mutate the value under a key. fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(key: &K, f: F, storage: &S) -> R;
因此,如果要將值 "insert" 到一個 Storage Map 中,則需要提供 key 和 value,如下所示:
<SomeValue<T>>::insert(key, value);
你可以使用以下任一方法查詢該值:
let my_value = <SomeValue<T>>::get(key); let also_my_value = Self::some_value_getter(key);
如下圖:
使用 StorageMap