操作資源 | Move dApp 極速入門(三)

語言: CN / TW / HK

MOVE 中的重要概念 —— 資源

本系列將以 Starcoin 為例,講解 Move 語言以及 Move dApp 的開發,及其背後的計算機原理。

本系列的全文更新中,見:

https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp

同步的打卡任務:

https://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-others

「資源」是 Move 語言中最關鍵的概念。本篇將以 Library 圖書館 Demo 為例,講解在 Rust 下是如何 操作資源 的。

0x01 原始碼下載

本文的 Demo 原始碼包含 smart contractreact dAppscript.sh 三部分,資源連結如下:

https://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp/my-library

0x02 Types with Abilities

https://move-book.com/advanced-topics/types-with-abilities.html#types-with-abilities

https://move-book.com/cn/advanced-topics/types-with-abilities.html

Move 的型別系統非常靈活,每種型別都可以定義四種能力(abilities)。它們決定了型別的值是否可以被「使用、丟棄和儲存」。

這四種 abilities 能力分別是: Copy, Drop, Store 和 Key。

它們的功能分別是:

  • Copy - 值可以被 複製
  • Drop - 在作用域(Scope)結束時值可以被 丟棄
  • Key - 值可以作為 鍵值(Key) 被「全域性儲存操作( global storage operations)」進行 訪問
  • Store - 值可以被 儲存 到全域性狀態。

在上一篇中,我們已經初步接觸到了 Abilities。在本例項中,我們將進一步的通過 Play with Abilities 掌握其原理。

0x03 Abilities 的語法

基本型別和內建型別的 abilities 是預先定義好的並且不可改變: integers, vector, addresses 和 boolean 型別的值先天具有 copy、drop 和 store ability。

然而,結構體的 ability 可以按照下面的語法進行新增:

struct NAME has ABILITY [, ABILITY] { [FIELDS] }

一個圖書館的 Struct 例子:

module Library {

    // each ability has matching keyword
    // multiple abilities are listed with comma
    struct Book has store, copy, drop {
        year: u64
    }

    // single ability is also possible
    struct Storage has key {
        books: vector<Book>
    }

    // this one has no abilities 
    struct Empty {}
}

0x04 Library 合約實踐

合約原始碼見:

https://github.com/WeLightProject/Web3-dApp-Camp/blob/main/move-dapp/my-library/sources/MyLibrary.move

對應的指令碼合集如下(指令碼中的路徑、地址等資訊需自行調整):

# deploy
dev deploy [path to blob] -s [addr] -b
dev deploy /Users/cjf/Documents/bc/Web3-dApp-Camp/move-dapp/my-library/release/my_library.v0.0.3.blob -s 0x07ffe973c72356c25e623e2470172a69 -b
# call function init library
account execute-function --function 0x07Ffe973C72356C25e623E2470172A69::MyLibrary::init_library -s 0x07Ffe973C72356C25e623E2470172A69 -b
# get library
state get resource 0x07Ffe973C72356C25e623E2470172A69 0x07Ffe973C72356C25e623E2470172A69::MyLibrary::Library
# add book
account execute-function --function 0x07Ffe973C72356C25e623E2470172A69::MyLibrary::s_add_book --arg b"web3" --arg b"github.com" -s 0x07Ffe973C72356C25e623E2470172A69 -b
# update book at index
account execute-function --function 0x07Ffe973C72356C25e623E2470172A69::MyLibrary::s_update_book_at_id --arg 0 --arg b"atest" --arg b"noncegeek.com" -s 0x07Ffe973C72356C25e623E2470172A69 -b
# delete book at index
account execute-function --function 0x07Ffe973C72356C25e623E2470172A69::MyLibrary::s_add_book --arg b"web3" --arg b"github.com" -s 0x07Ffe973C72356C25e623E2470172A69 -b

通過如下命令在 starcoin console 中進行合約部署:

starcoin% dev deploy [path to blob] -s [deployer addr] -b

初始化 Library:

starcoin% account execute-function --function [deployer addr]::MyLibrary::init_library -s [deployer addr] -b

檢視 Library:

starcoin% state get resource [caller addr] [deployer addr]::MyLibrary::Library

此時因為還沒有藏書,所以圖書館是空的:

插入一本 Book:

starcoin% account execute-function --function [deployer addr]::MyLibrary::s_add_book --arg b"web3" --arg b"github.com" -s [caller addr] -b

此時再執行 get resource ,會發現多了一個 item:

更新( Update )和刪除( Delete )的操作同理,你自己來動手試試吧:)!

0x05 Library 合約原始碼分析

Move 合約包含 Structfuncscript 三個部分。

其中, Struct 定義資料結構、 func 是一般函式、 script 是暴露被外部呼叫的指令碼。

module MyAddr::MyLibrary {
   use StarcoinFramework::Signer;
   use StarcoinFramework::Vector;
   // each ability has matching keyword
   // multiple abilities are listed with comma
   struct Book has store, copy, drop {
      id: u64,
      name: vector<u8>,
      link: vector<u8>
   }

   // single ability is also possible
   struct Library has key {
      books: vector<Book>
   }

   public fun create_library(account: &signer){
      move_to<Library>(account, Library{books: Vector::empty<Book>()});
   }
   //because the script function cannot have return value,
   //query only can be done by: state get resource Addr Addr::MyLibraryV4::Library
   public fun addBook(account: &signer,name:vector<u8>, link: vector<u8>) acquires  Library {
      let lib = borrow_global_mut<Library>(Signer::address_of(account));
      let id = Vector::length(&lib.books);
      Vector::push_back(&mut lib.books, Book{id:id,name:name,link:link});
   }

   public fun updateBookAtId(account: &signer,id:u64,name:vector<u8>, link: vector<u8>) acquires  Library {
      let lib = borrow_global_mut<Library>(Signer::address_of(account));
      let book = Vector::borrow_mut<Book>(&mut lib.books,id);
      book.name = name;
      book.link = link;
   }

   public fun deleteBookAtId(account: &signer,id:u64) acquires  Library {
      let lib = borrow_global_mut<Library>(Signer::address_of(account));
      Vector::remove(&mut lib.books, id);
   }

   public(script) fun init_library(account: signer){
      Self::create_library(&account)
   }

   public(script) fun s_add_book(account: signer, name:vector<u8>, link: vector<u8>) acquires  Library {
      Self::addBook(&account,name, link)
   }

   public(script) fun s_update_book_at_id(account: signer, id:u64,name:vector<u8>, link: vector<u8>) acquires  Library {
      Self::updateBookAtId(&account,id,name,link)
   }

   public(script) fun s_delete_book_at_id(account: signer, id:u64) acquires  Library {
      Self::deleteBookAtId(&account,id)
   }
}

5.1 move_to 函式

還記得 signer 嗎? 現在你可以看看它是如何運作的! 要將資源移動到帳戶,您有內建函式 move_to,它將 signer 作為第一個引數, Collection 作為第二個引數。 move_to 函式的簽名可以表示為:

native fun move_to<T: key>(account: &signer, value: T);

這導致兩個結論:

  • 您只能將資源放在您的帳戶下。 您無法訪問另一個帳戶的 signer value,因此無法將資源放在那裡。
  • 一個地址下只能儲存一種單一型別的資源。 兩次執行相同的操作會導致丟棄現有資源——這種情況絕不能發生(想象您儲存了您的硬幣,並且由於不準確的操作,您通過推空餘額丟棄了所有儲蓄!)。 第二次嘗試建立現有資源將失敗並出現錯誤。

—— https://move-book.com/resources/resource-by-example/storing-new-resource.html

在本 demo 中,我們通過 move_to 函式建立了 Library 資源:

public fun create_library(account: &signer){
    move_to<Library>(account, Library{books: Vector::empty<Book>()});
}

5.2 borrow_global & borrow_global_mut

見:

https://move-book.com/cn/resources/resource-by-example/access-resource-with-borrow.html#%E8%AF%BB%E5%8F%96%E5%92%8C%E4%BF%AE%E6%94%B9-resource

5.3 Vector

Vector 是 Rust 中的一種資料型別,其允許我們在一個單獨的資料結構中儲存多於一個的值,它在記憶體中彼此相鄰地排列所有的值。Vector 只能儲存相同型別的值。它們在擁有一系列項的場景下非常實用,例如檔案中的文字行或是購物車中商品的價格。

在本 Demo 中,我們使用 vector&lt;u8> 來統一處理字串,相當於 Python 中的 b"something",或 Elixir 中的 <<1,2,3>>。

此外,Library 中存放了很多書籍,我們能用 vector&lt;Book> 表示,相當於其他語言中的 List 型別:

struct Library has key {
    books: vector<Book>
}

要了解更多關於 Vector 的內容,可以見 starcoin-framework

https://github.com/starcoinorg/starcoin-framework/blob/3e24ac46c2ada60956bce1d104e7d7de3a42d849/sources/Vector.move

本文參與登鏈社群寫作激勵計劃 ,好文好收益,歡迎正在閱讀的你也加入。

  • 發表於 1分鐘前
  • 閱讀 ( 2 )
  • 學分 ( 0 )
  • 分類:Aptos
  • 專欄:狗哥區塊鏈精品內容集