近期 Sui 出了一个新的教程 Let‘s Move Sui, 所有的 lesson 我都做了一遍, 共享我的总结。 本文代码: github.com/upupnoah/mo…

Module (模块)

  • Move 代码被安排成模块, 能够把一个模块看成是区块链上的一个智能合约

  • 能够经过调用这些模块中的函数来与模块进行交互,能够经过业务或其他 Move 代码来实现, 业务将被发送到并由Sui区块链进行处理,一旦执行完结,成果的更改将被保存

  • 一个模块module 关键字 地址 模块名组成, 其间地址能够写成 alias (界说在 Move.toml中), 例如 lets_move_sui

    module lets_move_sui::sui_fren {
    }
    

基本数据类型

  • 无符号整数: u8,u16,u32,u64,u128,u256
  • Boolean: bool
  • Addresses: address
  • 字符串: String
  • Vector: vector, 例如 vector<u64>
  • 自界说的结构体类型, 例如下面界说的 Struct

Struct (结构体)

  • 结构体是 Sui Move 中的一个基本概念

  • 结构体能够看成是一组相关字段的组合, 每个字段都有自己的类型

  • Sui Move 能够为结构体增加4 种才能: key、store、drop、copy, 这些才能后续会慢慢触及

  • 下面是一个基本的结构体名为 AdminCap, 内部含有一个 num_frens字段

        public struct AdminCap {
            num_frens: u64,
        }
    
  • 增加一个私有函数 init, 这是一个特别的函数, 会在 module 部署到区块链时, 自动调用

        fun init(ctx: &mut TxContext) {
            let admin_cap = AdminCap {
                id: object::new(ctx),
                num_frens: 1000,
            };
            transfer::share_object(admin_cap);
        }
    

Object

  • Object 是 Sui 中的一个基本概念
  • 在 Sui 中, 所有数据能够视为不同 Object 内部的字段
  • 运用结构体(Struct)来表示Object
  • 能够依据 module 中界说的函数进行创立, 读取, 修正,交互 Object

创立一个 Object

  • 一个 Object 一般都有 key 才能以及含有一个类型为 UIDid 字段

    • sui::object::new : 创立一个新目标。返回有必要存储在 Sui 目标中的 UID

          public fun new(ctx: &mut TxContext): UID {
              UID {
                  id: ID { bytes: tx_context::fresh_object_address(ctx) },
              }
          }
      
  • 创立 Ticket: create_ticket

  • 示例代码

    module lets_move_sui::ticket_module {
        use sui::clock::{Self, Clock};
        use sui::object::{Self, ID, UID};
        use sui::transfer;
        use sui::tx_context::{Self, TxContext};
        public struct Ticket has key {
            id: UID,
        }
        public fun create_ticket(ctx: &mut TxContext, clock: &Clock) {
            let uid = object::new(ctx);
            let ticket = Ticket {
                id: uid,
                expiration_time: clock::timestamp_ms(clock),
            };
            transfer::transfer(ticket, tx_context::sender(ctx));
        }
    }
    

读取 Ojbect 中的字段

  • 一个 Ticket 一般都有过期时间

    • Ticket 结构体中增加一个 expiration_time 字段
    • ticket_module 中增加一个 is_expired 方法来检测是否过期
module lets_move_sui::ticket_module {
    use sui::clock::{Self, Clock};
    use sui::object::{Self, ID, UID};
    use sui::transfer;
    use sui::tx_context::{Self, TxContext};
    public struct Ticket has key {
        id: UID,
        expiration_time: u64,
    }
    public fun create_ticket(ctx: &mut TxContext, clock: &Clock) {
        let uid = object::new(ctx);
        let ticket = Ticket {
            id: uid,
            expiration_time: clock::timestamp_ms(clock),
        };
        transfer::transfer(ticket, tx_context::sender(ctx));
    }
    public fun is_expired(ticket: &Ticket, clock: &Clock): bool {
        ticket.expiration_time <= clock::timestamp_ms(clock)
    }
}

修正 Object 中的字段

  • 需求在函数中传入一个可变引证

    module 0x123::my_module {
       use std::vector;
       use sui::object::{Self, UID};
       use sui::transfer;
       use sui::tx_context::TxContext;
       struct MyObject has key {
           id: UID,
           value: u64,
       }
       fun init(ctx: &mut TxContext) {
           let my_object = MyObject {
               id: object::new(ctx),
               value: 10,
           };
           transfer::share_object(my_object);
       }
       public fun set_value(global_data: &mut MyObject, value: u64) {
           global_data.value = value;
       }
    }
    

删去一个 Object

  • sui::object::delete : 删去该目标及其 UID 。这是消除 UID 的仅有方法

        public fun delete(id: UID) {
            let UID { id: ID { bytes } } = id;
            delete_impl(bytes)
        }
    
  • 示例代码

    module 0x123::ticket_module {
      use sui::clock::{Self, Clock};
      use sui::object::{Self, UID};
      use sui::transfer;
      use sui::tx_context::TxContext;
      struct Ticket has key {
          id: UID,
          expiration_time: u64,
      }
      public fun clip_ticket(ticket: Ticket) {
         let Ticket {
             id,
             expiration_time: _,
         } = ticket;
         object::delete(id);
      }
    }
    

Math

  • 在 Move 中数学运算和其他编程言语非常类似
  • 需求注意的是 x^y 表示 以 x 为底, 指数为 y

类型转化

  • 相同的类型能够直接进行算术运算, 但是不同的类型之间想要进行算术运算, 则需求进行转化

  • 在 Move 中类型转化能够运用这种形式: (x as <type>), 例如(x as u64)

    fun mixed_types_math_error(): u64 {
       let x: u8 = 1;
       let y: u64 = 2;
       // This will fail to compile as x and y are different types. One is u8, the other is u64.
       x   y
    }
    fun mixed_types_math_ok(): u64 {
       let x: u8 = 1;
       let y: u64 = 2;
       // Ok
       (x as u64)   y
    }
    

Vector

  • vector 适当于是一个动态数组, 这是 Move 内置的一个数据结构, 后续会了解到更多

  • 创立 vector

       // The empty vector does not yet have a type declared. The first value added will determine its type.
       let empty_vector = vector[];
       let int_vector = vector[1, 2, 3];
       let bool_vector = vector[true, true, false];
    
  • vector in struct field

       struct MyObject has key {
           id: UID,
           values: vector<u64>,
           bool_values: vector<bool>,
           address_values: vector<address>,
       }
    

Public function and Private function

  • init 函数有必要是 Private 的, 它会在合约部署的时分由 Sui 虚拟机(VM)调用
  • Public 意味着它能够被任何其他的 Move moduletransactions 调用
  • Private 意味着只能被当时 Move module 调用, 而且不能从 transaction 中调用
module lets_move_sui::sui_fren {
    use sui::tx_context::{Self, TxContext};
    use sui::transfer;
    use sui::object::{Self, ID, UID};
    use std::string::String;
    // use std::vector; // built-in
    use sui::event;
    public struct AdminCap has key {
        id: UID,
        num_frens: u64,
    }
    public struct SuiFren has key {
        id: UID,
        generation: u64,
        birthdate: u64,
        attributes: vector<String>,
    }
    fun init(ctx: &mut TxContext) {
        let admin_cap = AdminCap {
            id: object::new(ctx),
            num_frens: 10^3, // 1000
        };
        transfer::share_object(admin_cap);
    }
    // change the mint function to transfer the object to the sender
    public fun mint(generation: u64, birthdate: u64, attributes: vector<String>, ctx: &mut TxContext) {
        let uid = object::new(ctx);
        let sui_fren = SuiFren {
            id: uid,
            generation,
            birthdate,
            attributes,
        };
        transfer::transfer(sui_fren, tx_context::sender(ctx));
    }
    public fun burn(sui_fren: SuiFren) {
        let SuiFren {
            id,
            generation: _,
            birthdate: _,
            attributes: _,
        } = sui_fren;
        object::delete(id);
    }
    public fun get_attributes(sui_fren: &SuiFren): vector<String> {
        sui_fren.attributes
    }
    public fun update_attributes(sui_fren: &mut SuiFren, attributes: vector<String>) {
        sui_fren.attributes = attributes;
    }
}

Shared Object and Owned Object

  • Shared Objects能够被任何用户读取和修正

    • 不能并行处理(例如修正), 而且需求严厉的查看, 性能慢, 可扩展性差
  • Owned Objects是私有目标,只要具有它们的用户才能读取和修正(所有权)

    • 只允许直接所有权,因而假如用户A具有目标B,而目标B具有目标C,则用户A无法发送包含目标C的业务, 这个问题能够运用 Receiving<T> 解决(后续会提及)
    • 能够并行处理, 因为触及它们的 transaction (业务) 不会相互堆叠
  • sui::transfer::share_object : 将给定的目标转化为一个可变的共享目标,每个人都能够拜访和修正

    public fun share_object<T: key>(obj: T) {
        share_object_impl(obj)
    }
    
  • sui::transfer::transfer : 将 obj 的所有权转移给接收者。obj 有必要具有 key 属性

    public fun transfer<T: key>(obj: T, recipient: address) {
        transfer_impl(obj, recipient)
    }
    
  • 示例代码

    module lets_move_sui::shared_and_owned {
        use sui::object::{Self, UID};
        use sui::tx_context::{Self, TxContext};
        use sui::transfer;
        public struct SharedObject has key {
            id: UID,
        }
        public struct OwnedObject has key {
            id: UID,
        }
        public fun create_shared_object(ctx: &mut TxContext) {
            let shared_object = SharedObject {
            id: object::new(ctx),
            };
            transfer::share_object(shared_object);
        }
        public fun create_owned_object(ctx: &mut TxContext) {
            let owned_object = OwnedObject {
                id: object::new(ctx),
            };
            transfer::transfer(owned_object, tx_context::sender(ctx));
        }
    }
    

Event (工作)

  • 什么是 Event? Event 是你的module 将区块链上产生的工作传达给应用程序前端的一种方法

  • 应用程序能够监听某些 Event 来采纳举动

  • Event 首要用来给”链下”组件 与 “链上”组件进行交互

  • sui::event::emit : 宣布自界说的 Move Event,将数据发送到链下。 由下面的函数签名可知, emit 的参数需求一个包含 copydrop 才能的类型

    public native fun emit<T: copy   drop>(event: T);
    
  • 示例代码

    module 0x123::ticket_module {
      use sui::clock::{Self, Clock};
      use sui::event;
      use sui::object::{Self, ID, UID};
      use sui::transfer;
      use sui::tx_context::{Self, TxContext};
      struct Ticket has key {
          id: UID,
          expiration_time: u64,
      }
      struct CreateTicketEvent has copy, drop {
         id: ID,
      }
      struct ClipTicketEvent has copy, drop {
         id: ID,
      }
       public fun create_ticket(ctx: &mut TxContext, clock: &Clock) {
         let uid = object::new(ctx);
         let id = object::uid_to_inner(&uid);
         let ticket = Ticket {
               id: uid,
               expiration_time: clock::timestamp_ms(clock),
         };
         transfer::transfer(ticket, tx_context::sender(ctx));
         event::emit(CreateTicketEvent {
             id,
         });
       }
      public fun clip_ticket(ticket: Ticket) {
         let Ticket { id, expiration_time: _ } = ticket;
         object::delete(id);
         event::emit(ClipTicketEvent {
            id: object::uid_to_inner(&id),
         });
      }
    }
    

总结

模块(module) 安排

Move代码被安排成模块,每个模块类似于其他区块链上的单个智能合约。这种模块化设计在Sui中得到了强调,旨在促使开发者坚持模块小巧且散布在不同文件中,一起坚持清晰的数据结构和代码标准。这样做既便利应用程序集成,也便于用户理解。

API和交互

模块经过进口和公共函数供给API,用户能够经过业务或其他Move代码调用这些函数来与模块交互。这些交互由Sui区块链处理,而且会保存任何成果变更。

结构体(Struct)

结构是由相关字段组成的集合,每个字段都有自己的类型,如数字、布尔值和向量。每个结构都能够具有“才能”,包括键(key)、存储(store)、放置(drop)、仿制(copy)。这些才能描绘了结构在言语中的行为方法。

数据类型 (data type)

Sui Move 支持以下数据类型:无符号整数、布尔值、地址、字符串、向量以及自界说结构类型

目标 (object)

理解目标的生命周期、如何阅览、更新以及删去目标是学习Move言语的重要部分。此外,还需求区别共享目标与具有目标的概念。

向量 (vector)

向量被理解为动态数组,关于办理智能合约中的项目列表至关重要,反映了区块链应用程序中关于灵敏数据结构的需求。

工作 (event)

工作是模块用来通知应用程序前端区块链上产生了某些工作的一种方法。应用能够监听特定的工作,并在这些工作产生时采纳举动。

函数 (fun)

  • 公共函数(运用关键字public):能够从任何其他Move模块和业务中被调用。
  • 私有函数(运用关键字private):只能在同一个模块中调用,不能从业务中调用。

加入安排, 一起沟通/学习!