最新內容會更新在主站深入淺出區塊鏈社區
原文鏈接:智能合約語言 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
目前我們也在招募體驗師,可以點擊鏈接了解。
參考文檔
深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術博客