以太坊智慧合約 Solidity 的常用資料型別介紹

Lion發表於2017-11-09

目錄

  Solidity 是一種靜態語言型別,在編譯前都要指定每個變數的型別。Solidity 提供了幾種基本型別,通過幾種基本型別的組合,可以組合成複雜型別。

  網路上有很多翻譯後的關於 Solidity 型別介紹的文章,這裡就不多介紹,只是著重介紹後面例項中會使用到的一些型別。

  上一章節中,我們講了 使用 Browser-solidity 在 Go-Ethereum1.7.2 上進行簡單的智慧合約部署,本文中後面的例項,都可以在 Browser-solidity 中進行測試。

  

1、陣列

  陣列是可以在編譯時固定大小的,也可以是動態的。對於儲存器陣列來說,成員型別可以是任意的(也可以是其他陣列,對映或結構)。對於記憶體陣列來說 ,成員型別不能是一個對映;如果是公開可見的函式引數,成員型別是必須是ABI型別的。

  固定大小k的陣列和基本型別 T,可以寫成 T[k], 動態陣列寫成 T[ ] 。例如, 有5個基本型別為 uint 的動態陣列的陣列 可以寫成 uint[ ][5] ( 注意,和一些其他語言相比,這裡的符號表示次序是反過來的)。為了訪問第三動態陣列中的第二個 uint, 必須使用 x[2][1](下標是從零開始的,訪問模式和宣告模式正好相反, 即x[2]是從右邊剔除了一階)。

  bytesstring 是特殊型別的陣列。 bytes 類似於 byte[ ],但它是緊湊排列在calldata裡的。string 等於 bytes , 但不允許用長度或所以索引訪問(現在情況是這樣的)。

  所以 bytes 應該優先於 byte[ ],因為它效率更高。

  

1.1、對陣列的增刪改查操作。

  在Browser-solidity的左側,新建一個mshk_top_array.sol檔案,內容如下:

  mshk_top_array.sol:

pragma solidity ^0.4.17;

/**
 * 陣列的增、刪、改、查
 * https://mshk.top
 */
contract mshk_top_array {

    //宣告一個全域性陣列變數
    uint[] public intArray;

    /*
     * 建構函式
     * 預設向陣列中新增一個2009
     */
    function mshk_top_array() public{
      intArray.push(2009);
    }

    /*
     * @dev 新增一個值到陣列
     * @param val uint, 要傳入的數值
     */
    function add(uint val) public{
        intArray.push(val);
    }

    /*
     * @dev 獲取陣列的長度
     * @return len uint,返回陣列的長度
     */
    function length() public view returns (uint) {
      return intArray.length;
    }

    /*
     * @dev 更新陣列的值
     * @param _index uint, 指定的索引
     * @param _value uint, 要修改的值
     */
    function update(uint _index, uint _value) public{
      intArray[_index] = _value;
    }

    /*
     * @dev 獲取指定陣列索引的值
     * @param _index uint, 索引值
     * @return _value uint, 返回結果
     */
    function valueByIndex(uint _index) public view returns (uint _value){
      uint result = intArray[_index];
      return result;
    }

    /*
     * @dev 刪除指定陣列索引的值
     * @param _index uint, 索引值
     */
    function delByIndex(uint _index) public{
      uint len=intArray.length;
      if (_index >= len) return;
      for (uint i = _index; i<len-1; i++){
        intArray[i] = intArray[i+1];
      }
      delete intArray[len-1];
      intArray.length--;
    }
}

Array型別有兩個成員,lengthpush

更多介紹參考連結: http://solidity.readthedocs.io/en/latest/types.html?highlight=uint#members

  
  在左側寫完程式碼以後,可以在右側的Setting選擇0.4.17+commit.bdeb9e52,然後在Run選項卡中,進行除錯。

  之前的文章中有介紹如何使用Browser-solidity除錯Solidity,本文中不多介紹,沒看過的同學,可以參考 這裡

<embed>

2、String、Bytes、Mapping的使用

  string型別沒有length屬性,而bytes型別有length屬性
  
  bytes1, bytes2, bytes3, ..., bytes32,如果在bytes後面帶了數字進行宣告時,最多可以儲存32個字元。一旦宣告以後,那麼length屬性就是你宣告的長度。
  
  mapping,是由鍵和值組成的mapping(_KeyType => _ValueType)雜湊表,初始化每個存在的key,對應的value的值會初始化為所有的位元組都為0。_KeyType_ValueType可以是任意型別。mapping只允許靜態變數或是內部方法中的儲存空間引用型別。一般鍵為地址, 值為餘額 mapping(address => uint)

string型別的官方介紹:http://solidity.readthedocs.io/en/latest/types.html?highlight=uint#string-literals
bytes陣列的官方介紹:http://solidity.readthedocs.io/en/latest/types.html?highlight=bytes#fixed-size-byte-arrays
Mappings型別的官方介紹:http://solidity.readthedocs.io/en/latest/types.html?highlight=bytes#mappings

  
  下面我們建立一個mshk_top_string_bytes_mapping.sol檔案,對stringbytesmapping進行測試。

  mshk_top_string_bytes_mapping.sol:

pragma solidity ^0.4.17;

/**
 * 對`string`、`bytes`、`mapping`進行測試
 * https://mshk.top
 */
contract mshk_top_string_bytes_mapping {

  //宣告一個變數
  string public str;
  bytes public byt;
  mapping(bytes10 => string) public map;

  /*
   * 初始化
   */
  function init() public{
    str = "abc";
    byt = "abc";
    map["mshk"] = "mshk.top";
    map["idoall"] = "idoall.org";
  }

  /*
   * @dev 獲取長度
   * @param uint 返回長度
   */
  function lenght() public view returns(uint){
    return byt.length;
  }

  /*
   * @dev 獲取map的指定key的值
   * @param _key bytes10,指定的key,如果key不存在,會返回空字串
   */
  function getMapByKey(bytes10 _key) public view returns(string){
    return map[_key];
  }
}

  
  下圖是在Browser-solidity中執行起來的效果:

<embed>

  

3、Enums 和 Structs 的簡單應用

  Enums是一個使用者可以定義型別的方法,可以使用uint轉換,預設從0開始遞增,但不可以隱性轉換,轉換失敗會丟擲異常,宣告Enums時,裡面至少要有一個成員。一般用來模擬合約的狀態。

  下面我們建立一個mshk_top_enums.sol檔案,對enums進行測試。

  mshk_top_enums.sol:

pragma solidity ^0.4.17;

/**
 * 對`enums`進行測試
 * https://mshk.top
 */
contract mshk_top_enums {

    //定義列舉
    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }

    //宣告變數
    ActionChoices choice;
    ActionChoices constant defaultChoice = ActionChoices.GoStraight;

    function setGoRight() public {
        choice = ActionChoices.GoRight;
    }

    function setGoLeft() public {
        choice = ActionChoices.GoLeft;
    }

    function setGoStraight() public {
        choice = ActionChoices.GoStraight;
    }

    function setSitStill() public {
        choice = ActionChoices.SitStill;
    }

    // Since enum types are not part of the ABI, the signature of "getChoice"
    // will automatically be changed to "getChoice() returns (uint8)"
    // for all matters external to Solidity. The integer type used is just
    // large enough to hold all enum values, i.e. if you have more values,
    // `uint16` will be used and so on.
    function getChoice() public view returns (ActionChoices) {
        return choice;
    }

    function getDefaultChoice() public pure returns (uint) {
        return uint(defaultChoice);
    }
}

  
  以上程式碼,第一次呼叫getChoice方法時,返回的值為0。呼叫setGoRight方法,對choice設定一個列舉值ActionChoices.GoRight,再次呼叫getChoice方法時,返回的值為1.

  下圖是在Browser-solidity中執行起來的效果:

<embed>

  
  Structs結構體,和其他語言一樣,可以定義任意型別的結構。Structs裡面可以定義Mappings,同樣在Mappings中也可以定義Structs。雖然結構本身可以作為mapping的成員值,但是結構不可以包含它本身型別,避免死迴圈。

  下面我們建立一個mshk_top_struct.sol檔案,對structs進行測試。

  mshk_top_struct.sol:

pragma solidity ^0.4.17;

/**
 * 對 structs 進行測試
 * https://mshk.top
 */
contract mshk_top_struct {

    // Defines a new type with two fields.
    struct User {
        string name;
        uint age;
    }

    //使用者列表
    User[] public users;

    /*
     * @dev 新增方法
     */
    function add(string _name, uint _age) public{
        users.push(
            User({
                name:_name,
                age:_age
            })
        );
    }
}

  以上程式碼,在add方法中,輸入"張三",18,然後在users中輸入索引值0,能夠看到如下圖中的效果:

<embed>

  
  Mapping型別被定義成如mapping(_KeyType => _ValueType)一樣,KeyTypeValueType 可以是任何型別,其中 ValueType 甚至也可以是Mapping型別。

  mshk_top_struct_mapping.sol:

pragma solidity ^0.4.17;

/**
 * 使用 struct 和 mapping 編寫一個簡單的智慧合約
 * https://mshk.top
 */
contract mshk_top_struct_mapping {

    mapping (address => uint) public balanceOf;
    address public owner;
    event Sent(address sender, address receiver, uint amount); //定義一個時間

    //獲取部署合約的賬戶地址, 並初始化該地址的餘額
    function mshk_top_struct_mapping() public{
        owner = msg.sender;
        balanceOf[owner] = 10000;
    }
    //賬戶地址交易
    function transfer(address _to, uint amount) public{
        if(balanceOf[msg.sender] < amount) {return;}  //進行判斷,防止傳送賬戶的餘額不足
        if(balanceOf[_to] + amount < balanceOf[_to]){return;}  //防止自己給自己轉賬,或遞迴呼叫(因為每次呼叫都有額外的花費)
        balanceOf[_to] += amount;
        balanceOf[msg.sender] -= amount;
        Sent(msg.sender,  _to, amount);   ///呼叫事件
    }

    //挖礦
    function mint(uint amount) public{
         balanceOf[owner] += amount;
    }

}

  以上程式碼,在Browser-solidity中建立以後,能夠看到如下圖中的效果:

<embed>

  

4、Ether 單位和 Time 單位

  Ether的單位關鍵字有wei, finney, szabo, ether,換算格式如下:

  • 1 ether = 1 * 10^18 wei;
  • 1 ether = 1 * 10^6 szabo;
  • 1 ehter = 1* 10^3 finney;

  mshk_top_ether.sol:

pragma solidity ^0.4.17;

/**
 * 對 比特幣 Ether 的幾個單位進行測試
 * https://mshk.top
 */
contract mshk_top_ether {

    // 定義全域性變數
    uint public balance;

    function mshk_top_ether() public{
        balance = 1 ether;  //1000000000000000000
    }

    function mshk_finney() public{
      balance = 1 finney; //1000000000000000
    }

    function mshk_szabo() public{
      balance = 1 szabo;  //1000000000000
    }

    function mshk_wei() public{
      balance = 1 wei; //1
    }
}

  以上程式碼,在Browser-solidity中建立以後,能夠看到如下圖中的效果:

<embed>

  
  Time的單位關鍵字有seconds, minutes, hours, days, weeks, years,換算格式如下:

  • 1 == 1 seconds
  • 1 minutes == 60 seconds
  • 1 hours == 60 minutes
  • 1 days == 24 hours
  • 1 weeks == 7 days
  • 1 years == 365 days

  mshk_top_time.sol:

pragma solidity ^0.4.17;

/**
 * 對 Time 單位進行測試
 * https://mshk.top
 */
contract mshk_top_time {

    // 定義全域性變數
    uint public _time;

    function mshk_top_time() public{
      _time = 100000000;
    }

    function mshk_seconds() public view returns(uint){
      return _time + 1 seconds; //100000001
    }

    function mshk_minutes() public view returns(uint){
      return _time + 1 minutes; //100000060
    }

    function mshk_hours() public view returns(uint){
      return _time + 1 hours; //100003600
    }

    function mshk_weeks() public view returns(uint){
      return _time + 1 weeks; //100604800
    }

    function mshk_years() public view returns(uint){
      return _time + 1 years; //131536000
    }
}

  以上程式碼,在Browser-solidity中建立以後,能夠看到如下圖中的效果:

<embed>

  

5、Address

  address型別是一個由 20 位元組長度的值(以太坊的地址)組成的。地址型別有很多成員變數,是所有合約的基礎。常用的兩個成員為:

  • <address>.balance,地址的餘額(單位為:wei)
  • <address>.transfer,傳送以太幣(單位為:wei)到一個地址,如果失敗會丟擲異常,會撤回傳送。

  mshk_top_address.sol:

pragma solidity ^0.4.17;

/**
 * 對 Address 的測試
 * https://mshk.top
 */
contract mshk_top_address {

    // 定義全域性變數
    address public _a;
    address public _b;

    function mshk_top_address() public{
      _a = msg.sender;  //呼叫合約使用者的地址
      _b = this;  //當前合約的地址
    }

    function geta() public view returns(address){
      return _a;
    }

    function getb() public view returns(address){
      return _b;
    }
}

  以上程式碼,在Browser-solidity中建立以後,能夠看到如下圖中的效果:

<embed>

6、更多資料型別介紹

  有興趣的同學,如果想看更多的資料型別介紹 ,可以參考 以太坊資料型別官方文件

7、相關文章

Tools and Technologies in the Ethereum Ecosystem

Solidity撰寫智慧合約與注意事項(一)

Types


博文作者:迦壹
部落格地址:以太坊智慧合約 Solidity 的常用資料型別介紹
轉載宣告:可以轉載, 但必須以超連結形式標明文章原始出處和作者資訊及版權宣告,謝謝合作!


相關文章