Solidity基礎教程3——引用類型

本教程使用的開發環境是一款在線編譯器——ChainIDE,具體的使用方法在之前的文章當中已經有講解過,有需要的同學可以自行查看。

網址:https://eth.chainide.com/

序言

以太坊的EVM就像四十年前的計算機一樣,由於儲存和計算的代價受制於全網的帶寬,需要對每次數據拷貝非常謹慎,我們對超過256位的變量(數組、結構體)儲存往往需要指定它的儲存位置。

同時由於它是一種靜態語言,每一個變量的類型都必須定義清楚,包括他的儲存位置,不同儲存類型的變量,賦值的方式也是不一樣的。

數組與結構體

數組。簡單理解來說可以是由多個相同的值類型構成的序列,序列的長度由用戶設定,或者可以設定爲可變長度。

如果數組的儲存地址爲storage的話,那麼值類型可以爲任何類型,如果儲存地址爲memory,則類型受到ABI類型的限制,不能爲address payablecontractenumstruct

我們通過一些例程來簡單瞭解一下數組,包括如何建立數組與遍歷數組。

pragma solidity >=0.4.22 <0.6.0;

contract Array{
    //設定固定長度uint數組並進行初始化
    uint[5] a = [1,2,3,5,5];      //設定一個長度爲5的uint數組,名字叫a

    function get_a_value() view public returns(uint)
    {
        return a[1];                       //返回值爲2
    }

    bytes9 b = 0x6c690338656363468e;       //定義一個長度爲9字節的值
    byte[] b1;                             //定義一個值類型爲byte的變長數組
    
    //向變長數組內輸出
    function set_b1_array() public returns(byte)
    {
        for (uint i=0;i<=b.length;i++)     //b.length指的是b數組的長度值
        {
            b1.push(b[i]);          //向數組b1內添加值
        }
        return b[1];                       //返回值爲69
    }
}

數組的定義方式就如上面例程所示,一開始設定值類型,然後在後面加入一個方括號,方括號內是數組的長度,如果要定義變長數組則方括號內爲空,接着加入一個空格,最後是數組的名字。

uint[5] a;           

數組類型有個可以調用的變量叫length,這個變量代表了數組的長度,可以通過這個變量來對數組進行遍歷和清空。

變長數組可以調用push函數在數組的尾部添加值,對於在全局設定的狀態變量來說,這種值的修改會使用到很多gas,使用時需慎重。

結構體。結構體就好像一個袋子裏有很多的貨物一樣,一個結構體內可以包含很多變量,每個變量都是屬於這個結構體的一部分。

結構體的keyword是struct,具體如何定義和調用可以通過下面的例程進行學習:

   //將結構體設置爲狀態變量
  uint eth_score = 100;
    Program eth=Program                             //創建一個結構體 名字爲eth
        (0x797206393eB6582ac86883fA623CB5A05021191D,
        eth_score,
        100, 
        false);  //在定義結構體時必須將初始化做好,對於賦值爲常量的值時,對應的儲存位置爲storage
    
    function set_eth_score(uint set_score) public {
        eth.score = set_score;
    }
    
    function get_eth_score() public view returns(uint)
    {
        return eth.score;
    }
  //將結構體設置爲局部變量
    function get_program_param() public pure returns (uint)
    {
        Program memory chainide=Program
        ({contract_address:0x797206393eB6582ac86883fA623CB5A05021191D,
        member_num: 10,
        score:99, 
        capitalize:true});  //在定義結構體時必須將初始化做好,對於賦值爲常量的值時,對應的儲存位置爲memory
        return(chainide.score);
    }

這個例程分別對將結構體設置爲狀態變量(storage),以及設置爲局部變量(memory)進行了分別舉例。

Solidity的語言規範是要在定義結構體時對這個結構體進行初始化,定義初始化有兩種方式,一種是根據之前定義的結構體順序進行變量的初始化定義,第二種是通過{key:word}的方式進行每個元素的初始化。

tips:通過eth.score的方式可以調用結構體內變量的值,同時也可以根據之前定義的值類型在returns當中進行設置,但是要注意的是在現在的solidity當中自定義的結構體類型是不可以作爲函數的返回值。

Storage和memory

在Solidity當中有兩個關鍵字memory(臨時儲存的變量)storage(永久儲存的變量),這兩個關鍵字在合約內有一些約定俗成的定義,我們可以先通過一個例程來簡單瞭解一下。

pragma solidity ^0.5.6;
contract Person {

    int public age1;                     //狀態變量 儲存在storage當中
    string public name1;

    function Person1(int age,string memory name) public{
          age1 = age;                    //局部變量 儲存在memory當中
          name1 = name;
    }

    function Person2 (string memory name3) pure public returns(string memory){       //局部變量  儲存在memory當中
          string memory name2 = name3;
          return (name2);        //局部變量  儲存在memory當中
    }
}

}

通過在編寫程序時,在變量類型和名字的中間加入memory和storage關鍵字,來對變量的存儲位置進行定義。有些定義是默認的,比如在function作用域以外的變量基本上都是通過storage進行存儲的,而函數的輸入參數和輸出參數基本上是memory。

如果函數當中對儲存位置爲storage的變量進行改變,就會需要用到gasfee,因爲storage的數值是存儲在區塊鏈上的,因此在寫程序時需要儘量減少對儲存類型爲storage的變量的賦值。

如果對儲存位置爲memory的變量進行賦值和調用,則是不需要用到gas的,如果函數內都是這種操作,則可以在函數的()後加上pure定義符,表示這個調用這個函數不需要用到gas。

有些更加深入的探索,比如這兩個不同儲存位置的變量之間的相互賦值,會如何影響對方的值,以及這種storage的指針是怎麼運行的,在參考資料當中有涉及,有興趣的朋友可以自己點擊查詢。

由於在不同版本的Solidity當中,對於變量的定義和使用的規則是不一樣的,因此建議大家在編寫程序的時候使用統一的編譯器版本。

今天的教程到這裏就結束了,希望大家有所收穫。

參考資料

Memory和storage的互相轉換

狀態變量與指針傳遞

內存與結構體

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章