Solidity源文件布局
pragma(版本雜注)
- 用于指定源文件的版本,表明編譯器的版本,例如 pragma solidity ^0.4.0
- ^用于指代版本號需要大于0.4.0但是不可以超過大的層級,必須小于0.5.0
- 也可以使用大于等于小于來指定版本
import(導入其它源文件)
- Solidity所支持的導入語句import,語法和JavaScript非常類似
- import “filename”;? 從“filenmae”中導入所有的全局富豪到當前的全局作用域中
- import * as symbolName from “filename”;? 創建一個新的全局符號symbolName,其成員均來自于“filename”中的全局符號
- import {symbol1 as alias ,symbol2} from "filename"; 創建新的全局符號alias和symbol2,分別從“fikename'”引用symbol1和symbol2
- import “filename” as symbolName;這條語句等同于import * as symbolName from “filename”;?
Solidity值類型
- 布爾(bool)可能的結果為字符常量值true或者false
- 整型(int/uint)分別表示有符號和無符號的不同位數的整型變量,支持關鍵字uint8到uint256(無符號,從8位到256位)以及int8到int256,每8位為一個步長進行遞增
- 定長浮點型(fixed/ufixed):表示各種大小的有符號的無符號的定長浮點型,在關鍵字ufixedMxN和fixedMxN中,M表示該類型占用的位數,N表示可用的小數的位數,這個必須要小于80
- 地址(address)存儲一個20字節的值(以太坊的地址的大小)
- 定長字節數組:關鍵字有bytes1、bytes2、bytes3,。。。,bytes32,如果沒有數字bytes就是不定長的
- 枚舉(enum)一種用戶可以定義類型的方法,與C語言類似,默認從0開始遞增,一般用于模擬合約的狀態
- 函數(function)一種表示函數的類型
Solidity引用類型
數組(Array)
- 數組可以在聲明的時候指定長度(定長數組),也可以動態調整大小(變長數組/動態數組)
- 對于存儲型(storage)的數組來說,元素的類型可以是任意的(即元素可以是數組類型、映射類型或者結構體)
- 對于內存型(memory)的數組來說,元素的類型不能是映射(mapping)類型
結構(Struct)
- Solidity 支持通過構造結構體的形式來定義新的類型
映射(Mapping)
- 映射可以看作哈希表,在實際的初始化過程中創建每一個可能的key,并且將其映射到字節形式全是0的值(類型默認值)
Solidity地址類型
address
- 地址類型存儲一個20字節的值(以太坊地址的大小),地址的類型也有成員變量,并作為所有合約的基礎
address payable(V0.5.0引入)
- 與地址類型基本相同,不過多出了transfer和send;兩個成員變量
兩者的區別和轉換
- Payable地址是可以發送ether的地址,普通的address是不可以的
- 允許從payable address到address的隱式轉換,而反過來的直接轉換是不可能的(唯一的方法是通過uint160來進行中間轉換)
- 從0.5.0版本起,合約不再是從地址類型派生而來,但是如果它有payable回退函數,那同樣可以顯示轉換為address或者addresspayable類型
具體
- <address>.balance(uint256) 該地址的ether余額,以Wei為單位
- <address payable>.transfer(uint256 amount) 向指定地址發送數量為amount的ether(以Wei為單位),失敗時拋出異常,發送23000gas的礦工費,不可以調節
- <address payable>.send(uint256 amount)returns(bool)向指定地址發送數量為amount的ether(以Wei為單位),失敗時返回false,發送23000gas的礦工費,不可以調節
- <address>.call(bytes memory)returns (bool,bytes memory) 發出底層函數CALL,失敗時候返回false,發送所有可用的gas,可以調節
- <address>.delegatecall(bytes memory)returns (bool,bytes memory)發出底層函數DELEGATECALL,失敗時候返回false,發送所有可用的gas,可以調節
- <address>.staticcall(bytes memory) returns(bool,bytes memory)發出底層函數STATICCALL,失敗時候返回false,發送所有可用的gas,可以調節
用法
balance和transfer
- 可以使用一個balance屬性來查詢一個地址的余額,可以使用tranafer函數像一個payable地址發送以太幣Ether(以wei為單位)
address payable x = address(0x123);
address myaddress = address(this);
if(x.balance < 10 && myaddress.balance >= 10)
x.transfer(10);
- 哪個地址調用transfer函數,就向哪個地址轉錢。以太坊的水管合約,發起交易實質是香我們的賬戶打錢
send
- send是transfer的初級版本。如果執行失敗,當前的合約不會因為異常而終止,但是send會返回false
call
- 通過添加call來實現轉幣操作,通過添加.gas()和.value()裝飾器
nameReg.call.gas(1000000).value(1 ether)(abi.encodeWithSignature("register(string)","MyName"));
字符數組(Byte Arrays)
定長字符數組
-
屬于值類型,bytes1、bytes2,。。。,bytes32分別代表了長度1到32的字節序列
-
有一個.length屬性,返回數組的長度(只讀)
變長字符數組
-
屬于引用類型,包括bytes和string,不同的是bytes是Hex字符串,而string是UTF-8編碼的字符串
數組
- 固定大小k和元素類型T的數組被寫成T[k],動態大小的數組為T[]。例,一個由5個uint動態數組組成的數組是uint[][5],和C語言不一樣,固定大小寫在數組的第二個[]里面
- 要訪問第三個動態數組中的第二個uint,可以使用x[2][1]
- 越界訪問數組,會導致調用失敗回退
- 如果要添加新的元素,則必須受用.push()或者將.length增大
- 變長的storage數組和bytes(不包括string)有一個push()方法。可以將一個新的元素附加到數組的末端,返回值為當前的數組長度
- 例子
pragma solidity >=0.4.16 <0.6.0
contract C{function f(uint len)public pure{uint[] memory a = new uint[](7);bytes memory b = new bytes(len);assert(a.length == 7);assert(b.length == len);a[6] = 8;}
}
枚舉
- 枚舉類型用來用戶自定義一組常量值
- 和C語言類似,對應整型值,從0開始累加
pragma solidity >=0.4.0 <0.6.0;
contract Purchase{enum Weekday {Monday,Thusday,Wednesday}function test() public pure returns(uint16){Weekday wd = Weekday.Wednesday;return uint16(wd);//2}
}
結構
- 結構體可以在映射和數組中使用,他們本身可以包含映射和數組
- 結構不能包含自己類型的成員,但是可以作為自己數組成員的類型,也可以作為自己映射成員的值類型
pragma solidity >=0.4.0 <0.6.0
contract Ballot{struct Voter{uint weight;bool voted;uint vote;}
}
映射(Mapping)
- 聲明一個映射 mapping(_KeyType => _ValueType)
- _KeyType可以是任何基本類型,這意味著它可以是任何內置值類型加上字符數組和字符串。不可以使用用戶定義的或者復雜的類型,如枚舉、映射、結構以及除了bytes和string之外任何數組類型。投票合約的時候,使用地址映射一個結構體,可以使用簡單結構來映射復雜結構,不可以使用復雜結構來映射簡單結構。本質上類似key-value的形式,使用簡單的結構來查詢復雜結構,但是不可以通過復雜結構來查詢簡單結構。
- _ValueType可以是任何類型,包括映射
例子
- 合約D調用合約C
pragma solidity ^0.4.0;
contract C{mapping (address => uint)balances;constructor(){balances[address(this)] = 300;}function updata(uint amount)public{balances[msg.sender] = amount;}function getBalance(address _addr)public returns (uint){return balances[_addr];}
}contract D{function fun() public returns(uint){C c = new C();//調用C合約c.update(10);//將C合約的復制了一份到D合約,將其改成了10return c.getBalance(address(c));//C合約的仍然是300return c.getBalance(address(this));//this指代當前合約D,合約是10return c.getBalance(msg.sender);//部署合約的地址,因此是0}
}
?