智慧合約語言 Solidity 教程系列6 - 結構體與對映

Tiny熊發表於2017-12-28

最新內容會更新在主站深入淺出區塊鏈社群
原文連結:智慧合約語言 Solidity 教程系列6 - 結構體與對映

寫在前面

Solidity 是以太坊智慧合約程式語言,閱讀本文前,你應該對以太坊、智慧合約有所瞭解,
如果你還不瞭解,建議你先看以太坊是什麼

本系列文章一部分是參考Solidity官方文件(當前最新版本:0.4.20)進行翻譯,另一部分是Solidity深入分析,這部分請訂閱區塊鏈技術專欄閱讀。

結構體(Structs)

Solidity提供struct來定義自定義型別,自定義的型別是引用型別。
我們看看下面的例子:

pragma solidity ^0.4.11;

contract CrowdFunding {
    // 定義一個包含兩個成員的新型別
    struct Funder {
        address addr;
        uint amount;
    }

    struct Campaign {
        address beneficiary;
        uint fundingGoal;
        uint numFunders;
        uint amount;
        mapping (uint => Funder) funders;
    }

    uint numCampaigns;
    mapping (uint => Campaign) campaigns;

    function newCampaign(address beneficiary, uint goal) public returns (uint campaignID) {
        campaignID = numCampaigns++; // campaignID 作為一個變數返回
        // 建立一個結構體例項,儲存在storage ,放入mapping裡
        campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
    }

    function contribute(uint campaignID) public payable {
        Campaign storage c = campaigns[campaignID];
        // 用mapping對應項建立一個結構體引用
        // 也可以用 Funder(msg.sender, msg.value) 來初始化.
        c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value});
        c.amount += msg.value;
    }

    function checkGoalReached(uint campaignID) public returns (bool reached) {
        Campaign storage c = campaigns[campaignID];
        if (c.amount < c.fundingGoal)
            return false;
        uint amount = c.amount;
        c.amount = 0;
        c.beneficiary.transfer(amount);
        return true;
    }
}

上面是一個簡化版的眾籌合約,但它可以讓我們理解structs的基礎概念,struct可以用於對映和陣列中作為元素。其本身也可以包含對映和陣列等型別。

不能宣告一個struct同時將自身struct作為成員,這個限制是基於結構體的大小必須是有限的。
struct可以作為mapping的值型別成員。

注意在函式中,將一個struct賦值給一個區域性變數(預設是storage型別),實際是拷貝的引用,所以修改區域性變數值的同時,會影響到原變數。

當然,也可以直接通過訪問成員修改值,而不用一定賦值給一個區域性變數,如campaigns[campaignID].amount = 0

對映(Mappings)

對映型別,一種鍵值對的對映關係儲存結構。定義方式為mapping(_KeyType => _KeyValue)。鍵型別允許除對映、變長陣列、合約、列舉、結構體外的幾乎所有型別()。值型別沒有任何限制,可以為任何型別包括對映型別。

對映可以被視作為一個雜湊表,所有可能的鍵會被虛擬化的建立,對映到一個型別的預設值(二進位制的全零表示)。在對映表中,並不儲存鍵的資料,僅僅儲存它的keccak256雜湊值,這個雜湊值在查詢值時需要用到。
正因為此,對映是沒有長度的,也沒有鍵集合或值集合的概念。

對映型別,僅能用來作為狀態變數,或在內部函式中作為storage型別的引用。

可以通過將對映標記為public,來讓Solidity建立一個訪問器。通過提供一個鍵值做為引數來訪問它,將返回對應的值。
對映的值型別也可以是對映,使用訪問器訪問時,要提供這個對映值所對應的鍵,不斷重複這個過程。
來看一個例子:

pragma solidity ^0.4.0;

contract MappingExample {
    mapping(address => uint) public balances;

    function update(uint newBalance) public {
        balances[msg.sender] = newBalance;
    }
}

contract MappingUser {
    function f() public returns (uint) {
        MappingExample m = new MappingExample();
        m.update(100);
        return m.balances(this);
    }
}

注意:
對映並未提供迭代輸出的方法,可以自行實現一個這樣的資料結構。參考iterable mapping

參考視訊

我們也推出了目前市面上最全的視訊教程:深入詳解以太坊智慧合約語言Solidity
目前我們也在招募體驗師,可以點選連結瞭解。

參考文件

Solidity官方文件

深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術部落格

相關文章