在Rust中,Struct(结构体)是一种自定义的数据结构,可以对其命名和将多个有意义的关联数据打包成一组。 Rust中的Struct类似面向对象语言(Java、C++)中的类(class),不过Rust中的Struct只包含对象的属性,不包含其方法。 编写模块代码 修改pallets/template/src/lib.rs的代码如下: #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ codec::{Decode, Encode}, decl_event, decl_module, decl_storage, dispatch::DispatchResult, }; use frame_system::{self as system, ensure_signed}; use sp_runtime::RuntimeDebug; pub trait Trait: balances::Trait + system::Trait { type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>; } #[derive(Encode, Decode, Clone, Default, RuntimeDebug)] pub struct InnerThing<Hash, Balance> { number: u32, hash: Hash, balance: Balance, } type InnerThingOf<T> = InnerThing<<T as system::Trait>::Hash, <T as balances::Trait>::Balance>; #[derive(Encode, Decode, Default, RuntimeDebug)] pub struct SuperThing<Hash, Balance> { super_number: u32, inner_thing: InnerThing<Hash, Balance>, } decl_storage! { trait Store for Module<T: Trait> as NestedStructs { InnerThingsByNumbers get(fn inner_things_by_numbers): map hasher(blake2_128_concat) u32 => InnerThingOf<T>; SuperThingsBySuperNumbers get(fn super_things_by_super_numbers): map hasher(blake2_128_concat) u32 => SuperThing<T::Hash, T::Balance>; } } decl_event!( pub enum Event<T> where <T as system::Trait>::Hash, <T as balances::Trait>::Balance { NewInnerThing(u32, Hash, Balance), NewSuperThingByExistingInner(u32, u32, Hash, Balance), NewSuperThingByNewInner(u32, u32, Hash, Balance), } ); decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { fn deposit_event() = default; #[weight = 10_000] fn insert_inner_thing(origin, number: u32, hash: T::Hash, balance: T::Balance) -> DispatchResult { let _ = ensure_signed(origin)?; let thing = InnerThing {number, hash, balance}; <InnerThingsByNumbers<T>>::insert(number, thing); Self::deposit_event(RawEvent::NewInnerThing(number, hash, balance)); Ok(()) } #[weight = 10_000] fn insert_super_thing_with_existing_inner(origin, inner_number: u32, super_number: u32) -> DispatchResult { let _ = ensure_signed(origin)?; let inner_thing = Self::inner_things_by_numbers(inner_number); let super_thing = SuperThing { super_number, inner_thing: inner_thing.clone(), }; <SuperThingsBySuperNumbers<T>>::insert(super_number, super_thing); Self::deposit_event(RawEvent::NewSuperThingByExistingInner(super_number, inner_thing.number, inner_thing.hash, inner_thing.balance)); Ok(()) } #[weight = 10_000] fn insert_super_thing_with_new_inner(origin, inner_number: u32, hash: T::Hash, balance: T::Balance, super_number: u32) -> DispatchResult { let _ = ensure_signed(origin)?; let inner_thing = InnerThing { number: inner_number, hash, balance, }; <InnerThingsByNumbers<T>>::insert(inner_number, inner_thing.clone()); Self::deposit_event(RawEvent::NewInnerThing(inner_number, hash, balance)); let super_thing = SuperThing { super_number, inner_thing, }; <SuperThingsBySuperNumbers<T>>::insert(super_number, super_thing); Self::deposit_event(RawEvent::NewSuperThingByNewInner(super_number, inner_number, hash, balance)); Ok(()) } } } 下面详细分析模块代码。 配置Cargo.toml 使用了sp_runtime和balances模块,需要在Cargo.toml中进行配置。 [dependencies]下添加: sp-runtime = { version = '2.0.0', default-features = false } balances = { package = 'pallet-balances', version = '2.0.0', default-features = false } [features]的std数组下添加: 'balances/std', 'sp-runtime/std', 定义一个Struct 为Substrate Runtime定义一个简单的结构体,使用如下语法: #[derive(Encode, Decode, Default, Clone, PartialEq)] pub struct MyStruct { some_number: u32, optional_number: Option<u32>, } 上面的代码片段声明了derive(派生)宏,以确保MyStruct的指定特征(Encode、Decode、Default、Clone、PartialEq)符合共享行为。 如果希望将此struct存储在区块链上,则需要派生或手动implement这些特征。 为了使用Encode和Decode特征,需要先导入: use frame_support::codec::{Encode, Decode}; 自定义#[derive]宏 自定义#[derive]宏在结构体和枚举上指定通过derive属性添加代码,是一种过程宏。 编译器能够通过#[derive]属性为某些traits提供基本实现,如果需要更复杂的行为,仍可以手动实现这些traits。 以下是可派生(derivable)特征(Traits)的列表: 比较特征:Eq、PartialEq、Ord、PartialOrd;Copy,用类型的“复制语义”代替“移动语义”;Clone,通过副本从&T创建T;Hash,从&T计算哈希值;Default,创建一个数据类型的空实例;Debug,使用{:?}格式化一个值;具有pallet通用字段的Struct 上面定义的Struct仅使用了Rust的基本数据类型,通常情况下如果想存储来自pallet的配置特征,则必须在Struct的定义中使用通用类型参数。 代码如下: #[derive(Encode, Decode, Clone, Default, RuntimeDebug)] pub struct InnerThing<Hash, Balance> { number: u32, hash: Hash, balance: Balance, } 可以看到,这里在Struct中使用了Hash和Balance类型,这两个类型是来自system和balances模块的配置traits,在声明结构体时需要将它们指定成范型。 通常以pallet的配置特征T作为单个参数类型别名,这样可以节省将来的输入: type InnerThingOf<T> = InnerThing<<T as system::Trait>::Hash, <T as balances::Trait>::Balance>; 使用Struct作为存储对象 使用Struct作为存储对象时与使用基本类型时没有明显区别,使用泛型结构时需要提供所有泛型类型参数。 decl_storage! { trait Store for Module<T: Trait> as NestedStructs { InnerThingsByNumbers get(fn inner_things_by_numbers): map hasher(blake2_128_concat) u32 => InnerThingOf<T>; SuperThingsBySuperNumbers get(fn super_things_by_super_numbers): map hasher(blake2_256) u32 => SuperThing<T::Hash, T::Balance>; } } 与存储映射进行交互的方式与不使用任何自定义结构时完全相同: fn insert_inner_thing(origin, number: u32, hash: T::Hash, balance: T::Balance) -> DispatchResult { let _ = ensure_signed(origin)?; let thing = InnerThing {number, hash, balance}; <InnerThingsByNumbers<T>>::insert(number, thing); Self::deposit_event(RawEvent::NewInnerThing(number, hash, balance)); Ok(()) } 嵌套Struct 结构体可以包含其他结构体做为其字段,内部结构体所需的任何泛型类型也必须提供给外部: #[derive(Encode, Decode, Default, RuntimeDebug)] pub struct SuperThing<Hash, Balance> { super_number: u32, inner_thing: InnerThing<Hash, Balance>, } 编译 编译命令如下: cd substrate-node-template cargo +nightly-2020-08-23 build --release 使用了nightly-2020-08-23这个较稳定的cargo nightly版本以避免编译过程中出现bug。 测试 启动node-template ./target/release/node-template --dev 打开https://polkadot.js.org/apps,切换网络为DEVELOPMENT-Local Node: 选项卡选择开发者-交易,“提交下面的外部信息”选择templateModule,会自动获取到定义的函数: insertInnerThing(number, hash, balance)insertSuperThingWithExistingInner(inner_number, super_number)insertSuperThingWithNewInner(inner_number, hash, balance, super_number)这里选择调用insertInnerThing函数,设定参数number为20,hash为默认值,balance为1000Unit。 点击右下角“提交交易”按钮,点击“签名并提交”: 就会调用decl_module!中定义的insert_inner_thing函数,并触发事件NewInnerThing。 选项卡选择网络-浏览-链信息,在右侧可以看到最新触发的事件: 可以看到触发的事件是模块代码中定义的templateModule.NewInnerThing。 —- 编译者/作者:松果 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
【Substrate开发教程】21 - Substrate Runtime中使用Struct结构体
2020-11-05 松果 来源:区块链网络
LOADING...
相关阅读:
- 上海国际区块链周Web3大会告诉了我们什么?2020-11-04
- 11.3以太坊行情分析及操作建议讲解2020-11-03
- 孙宇晨说:“恶意合同”使Tron区块链停滞了几个小时2020-11-03
- GFTB#7:Chainlink VRF和与Patrick Collins进行的游戏2020-11-02
- 上线只是开始发展方得始终2020-11-02