本文主要內容來自:https://solidity-cn.readthedocs.io/zh/latest/
三、型別
Solidity 是一種靜態型別語言,這意味著每個變數(狀態變數和區域變數)都需要在編譯時指定變數的型別(或至少可以推匯出變數型別)。Solidity 提供了幾種基本型別,可以用來組合出復雜型別。
除此之外,型別之間可以在包含運算子號的運算式中進行互動。
3.1 值型別
以下型別也稱為值型別,因為這些型別的變數將始終按值來傳遞。 也就是說,當這些變數被用作函式引數或者用在賦值陳述句中時,總會進行值拷貝。
布爾型別:
bool :可能的取值為字面常數值 true 和 false 。
運算子:
! (邏輯非)
&& (邏輯與, "and" )
|| (邏輯或, "or" )
== (等于)
!= (不等于)
運算子 || 和 && 都遵循同樣的短路( short-circuiting )規則。就是說在運算式 f(x) || g(y)中, 如果 f(x) 的值為 true ,那么 g(y) 就不會被執行,即使會出現一些副作用。
整型:
int / uint :分別表示有符號和無符號的不同位數的整型變數。 支持關鍵字 uint8 到 uint256(無符號,從 8 位到 256 位)以及 int8 到 int256,以 8 位為步長遞增。 uint 和 int 分別是 uint256 和 int256 的別名。
運算子:
比較運算子: <= , < , == , != , >= , > (回傳布林值)
位運算子: & , | , ^ (異或), ~ (位取反)
算數運算子: + , - , 一元運算 - , 一元運算 + , * , / , % (取余) , **(冪), << (左移位) , >> (右移位)
除以零或者模零運算都會引發運行時例外。
移位運算的結果取決于運算子左邊的型別。
運算式 x << y 與 x * 2**y 是等價的, x >> y 與 x / 2**y 是等價的。這意味對一個負
數進行移位會導致其符號消失。 按負數位移動會引發運行時例外。
警告:
由有符號整數型別負值右移所產生的結果跟其它語言中所產生的結果是不同的。 在 Solidity 中,右移和除是等價的,因此對一個負數進行右移操作會導致向 0 的取整(截斷)。 而在其它語言中, 對負數進行右移類似于(向負無窮)取整。
3.2 地址型別
address:地址型別存盤一個 20 位元組的值(以太坊地址的大小)。 地址型別也有成員變數,并作為所有合約的基礎。
運算子:
<=, <, ==, !=, >= 和 >
從 0.5.0 版本開始,合約不會從地址型別派生,但仍然可以顯式地轉換成地址型別。
地址型別成員變數
balance 和 transfer
可以使用 balance 屬性來查詢一個地址的余額, 也可以使用 transfer 函式向一個地址發送以太幣Ether (以wei為單位):
address x = 0x123;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
如果 x 是一個合約地址,它的代碼(更具體來說是它的 fallback 函式,如果有的話)會跟 transfer 函式呼叫一起執行(這是 EVM 的一個特性,無法阻止)。 如果在執行程序中用光了 gas 或者因為任何原因執行失敗,以太幣Ether 交易會被打回,當前的合約也會在終止的同時拋出例外。
此外,為了與不符合 應用二進制介面Application Binary Interface(ABI) 的合約互動,于是就有了可以接受任意型別任意數量引數的 call 函式。 這些引數會被打包到以 32 位元組為單位的連續區域中存放。 其中一個例外是當第一個引數被編碼成正好 4 個位元組的情況。 在這種情況下,這個引數后邊不會填充后續引數編碼,以允許使用函式簽名。
address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
nameReg.call("register", "MyName");
nameReg.call(bytes4(keccak256("fun(uint256)")), a);
call 回傳的布林值表明了被呼叫的函式已經執行完畢(true)或者引發了一個 EVM 例外(false)。 無法訪問回傳的真實資料(為此我們需要事先知道編碼和大小)。
所有合約都繼承了地址(address)的成員變數,因此可以使用 this.balance 查詢當前合約的余額。
任何未知的合約都可能是惡意的。
你在呼叫一個合約的同時就將控制權交給了它,它可以反過來呼叫你的合約, 因此,當呼叫回傳時要為你的狀態變數的改變做好準備。
3.3 定長位元組陣列
關鍵字有:bytes1, bytes2, bytes3, ..., bytes32。byte 是 bytes1 的別名。
運算子:
比較運算子:<=, <, ==, !=, >=, > (回傳布爾型)
位運算子: &, |, ^ (按位異或), ~ (按位取反), << (左移位), >> (右移位)
索引訪問:如果 x 是 bytesI 型別,那么 x[k] (其中 0 <= k < I)回傳第 k 個位元組(只讀)。
該型別可以和作為右運算元的任何整數型別進行移位運算(但回傳結果的型別和左運算元型別相同),右運算元表示需要移動的位數。 進行負數位移運算會引發運行時例外。
成員變數:
.length 表示這個位元組陣列的長度(只讀).
可以將 byte[] 當作位元組陣列使用,但這種方式非常浪費存盤空間,準確來說,是在傳入呼叫時,每個元素會浪費 31 位元組。 更好地做法是使用 bytes。
3.4 有理數和整數字面常數
整數字面常數由范圍在 0-9 的一串數字組成,表現成十進制。 例如,69 表示數字 69。 Solidity 中是沒有八進制的,因此前置 0 是無效的。
十進制小數字面常數帶有一個 .,至少在其一邊會有一個數字。 比如:1.,.1,和 1.3。
科學符號也是支持的,盡管指數必須是整數,但底數可以是小數。 比如:2e10, -2e10, 2e-10, 2.5e1。
數值字面常數運算式本身支持任意精度,除非它們被轉換成了非字面常數型別(也就是說,當它們出現在非字面常數運算式中時就會發生轉換)。 這意味著在數值常量運算式中, 計算不會溢位而除法也不會截斷。
例如, (2**800 + 1) - 2**800 的結果是字面常數 1 (屬于 uint8 型別),盡管計算的中
間結果已經超過了 以太坊虛擬機Ethereum Virtual Machine(EVM) 的機器字長度。
此外, .5 * 8 的結果是整型 4 (盡管有非整型參與了計算)。
只要運算元是整型,任意整型支持的運算子都可以被運用在數值字面常數運算式中。 如果兩個中的任一個數是小數,則不允許進行位運算。如果指數是小數的話,也不支持冪運算(因為這樣可能會得到一個無理數)。
在早期版本中,整數字面常數的除法也會截斷,但在現在的版本中,會將結果轉換成一個有理數。即 5 / 2 并不等于 2,而是等于 2.5。
數值字面常數運算式只要在非字面常數運算式中使用就會轉換成非字面常數型別。 在下面的例子中,盡管我們知道 b 的值是一個整數,但 2.5 + a 這部分運算式并不進行型別檢查,因此編譯不能通過。
uint128 a = 1;
uint128 b = 2.5 + a + 0.5;
3.5 列舉型別
pragma solidity ^0.4.16;
contract test {
enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
ActionChoices choice;
ActionChoices constant defaultChoice = ActionChoices.GoStraight;
function setGoStraight() public {
choice = ActionChoices.GoStraight;
}
// 由于列舉型別不屬于 |ABI| 的一部分,因此對于所有來自 Solidity 外部的呼叫,
// "getChoice" 的簽名會自動被改成 "getChoice() returns (uint8)"。
// 整數型別的大小已經足夠存盤所有列舉型別的值,隨著值的個數增加,
// 可以逐漸使用 `uint16` 或更大的整數型別。
function getChoice() public view returns (ActionChoices) {
return choice;
}
function getDefaultChoice() public pure returns (uint) {
return uint(defaultChoice);
}
}
3.6 資料位置
所有的復雜型別,即陣列和結構型別,都有一個額外屬性,“資料位置”,說明資料是保存在記憶體memory中還是存盤storage 中。
根據背景關系不同,大多數時候資料有默認的位置,但也可以通過在型別名后增加關鍵字 storage 或 memory 進行修改。 函式引數(包括回傳的引數)的資料位置默認是 memory, 區域變數的資料位置默認是 storage,狀態變數的資料位置強制是 storage 。
也存在第三種資料位置, calldata ,這是一塊只讀的,且不會永久存盤的位置,用來存盤函式引數。
外部函式的引數(非回傳引數)的資料位置被強制指定為 calldata ,效果跟 memory 差不多。
資料位置的指定非常重要,因為它們影響著賦值行為:
在存盤storage 和記憶體memory 之間兩兩賦值,或者存盤storage向狀態變數(甚至是從其它狀態變數)賦值都會創建一份獨立的拷貝。
然而狀態變數向區域變數賦值時僅僅傳遞一個參考,而且這個參考總是指向狀態變數,因此后者改變的同時前者也會發生改變。
另一方面,從一個 記憶體memory 存盤的參考型別向另一個 記憶體memory 存盤的參考型別賦值并不會創建拷貝。
pragma solidity ^0.4.0;
contract C {
uint[] x; // x 的資料存盤位置是 storage
// memoryArray 的資料存盤位置是 memory
function f(uint[] memoryArray) public {
x = memoryArray; // 將整個陣列拷貝到 storage 中,可行
var y = x; // 分配一個指標(其中 y 的資料存盤位置是 storage),可行
y[7]; // 回傳第 8 個元素,可行
y.length = 2; // 通過 y 修改 x,可行
delete x; // 清除陣列,同時修改 y,可行
// 下面的就不可行了;需要在 storage 中創建新的未命名的臨時陣列, /
// 但 storage 是“靜態”分配的:
// y = memoryArray;
// 下面這一行也不可行,因為這會“重置”指標,
// 但并沒有可以讓它指向的合適的存盤位置。
// delete y;
g(x); // 呼叫 g 函式,同時移交對 x 的參考
h(x); // 呼叫 h 函式,同時在 memory 中創建一個獨立的臨時拷貝
}
function g(uint[] storage storageArray) internal {}
function h(uint[] memoryArray) public {}
}
總結
強制指定的資料位置:
外部函式的引數(不包括回傳引數): calldata
狀態變數: storage
默認資料位置:
函式引數(包括回傳引數): memory
所有其它區域變數: storage
3.7 陣列
陣列可以在宣告時指定長度,也可以動態調整大小。
對于存盤storage 的陣列來說,元素型別可以是任意的(即元素也可以是陣列型別,映射型別或者結構體)。 對于記憶體memory 的陣列來說,元素型別不能是映射型別,如果作為 public 函式的引數,它只能是 ABI 型別。
一個元素型別為T,固定長度為k 的陣列可以宣告為T[k],而動態陣列宣告為 T[]。
舉個例子,一個長度為 5,元素型別為 uint 的動態陣列的陣列,應宣告為 uint[][5] (注意這里跟其它語言比,陣列長度的宣告位置是反的)。 要訪問第三個動態陣列的第二個元素,你應該使用 x[2][1](陣列下標是從 0 開始的,且訪問陣列時的下標順序與宣告時相反,也就是說,x[2] 是從右邊減少了一級)。
bytes 和 string 型別的變數是特殊的陣列。 bytes 類似于 byte[],但它在 calldata 中會被“緊打包”(譯者注:將元素連續地存在一起,不會按每 32 位元組一單元的方式來存放)。 string 與 bytes 相同,但(暫時)不允許用長度或索引來訪問。
創建記憶體陣列
可使用 new 關鍵字在記憶體中創建變長陣列。 與 存盤storage 陣列相反的是,你不能通過修改成員變數 .length 改變記憶體memory 陣列的大小。
pragma solidity ^0.4.16;
contract C {
function f(uint len) public pure {
uint[] memory a = new uint[](7);
bytes memory b = new bytes(len);
// 這里我們有 a.length == 7 以及 b.length == len
a[6] = 8;
}
}
陣列字面常數是寫作運算式形式的陣列,并且不會立即賦值給變數。
pragma solidity ^0.4.16;
contract C {
function f() public pure {
g([uint(1), 2, 3]);
}
function g(uint[3] _data) public pure {
// ...
}
}
陣列字面常數是一種定長的 記憶體memory 陣列型別,它的基礎型別由其中元素的普通型別決定。
例如,[1, 2, 3] 的型別是 uint8[3] memory,因為其中的每個字面常數的型別都是 uint8。 正因為如此,有必要將上面這個例子中的第一個元素轉換成 uint 型別。
目前需要注意的是,定長的記憶體memory陣列并不能賦值給變長的記憶體memory 陣列。
成員
length:
陣列有 length 成員變數表示當前陣列的長度。
動態陣列可以在存盤storage (而不是 記憶體memory )中通過改變成員變數 .length 改變陣列大小。 并不能通過訪問超出當前陣列長度的方式實作自動擴展陣列的長度。
一經創建,記憶體memory 陣列的大小就是固定的(但卻是動態的,也就是說,它依賴于運行時的引數)。
push:
變長的存盤storage陣列以及 bytes 型別(而不是 string 型別)都有一個叫做 push 的成員函式,它用來附加新的元素到陣列末尾。 這個函式將回傳新的陣列長度。
在外部函式中目前還不能使用多維陣列。
3.8 結構體
Solidity 支持通過構造結構體的形式定義新的型別,以下是一個結構體使用的示例:
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 中。我們先不關注映射型別。
campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
}
function contribute(uint campaignID) public payable {
Campaign storage c = campaigns[campaignID];
// 以給定的值初始化,創建一個新的臨時 memory 結構體,
// 并將其拷貝到 storage 中。
// 注意你也可以使用 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;
}
}
上面的合約只是一個簡化版的眾籌合約,但它已經足以讓我們理解結構體的基礎概念。 結構體型別可以作為元素用在映射和陣列中,其自身也可以包含映射和陣列作為成員變數。
盡管結構體本身可以作為映射的值型別成員,但它并不能包含自身。 這個限制是有必要的,因為結構體的大小必須是有限的。
注意在函式中使用結構體時,一個結構體是如何賦值給一個區域變數(默認存盤位置是 存盤storage )的。 在這個程序中并沒有拷貝這個結構體,而是保存一個參考,所以對區域變數成員的賦值實際上會被寫入狀態。
當然,你也可以直接訪問結構體的成員而不用將其賦值給一個區域變數,就像這樣,campaigns[campaignID].amount = 0。
3.9 映射
映射型別在宣告時的形式為 mapping(_KeyType => _ValueType)。
其中 _KeyType 可以是除了映射、變長陣列、合約、列舉以及結構體以外的幾乎所有型別。 _ValueType 可以是包括映射型別在內的任何型別。
映射可以視作哈希表 <https://en.wikipedia.org/wiki/Hash_table>,它們在實際的初始化程序中創建每個可能的 key, 并將其映射到位元組形式全是零的值:一個型別的默認值。然而下面是映射與哈希表不同的地方: 在映射中,實際上并不存盤 key,而是存盤它的 keccak256 哈希值,從而便于查詢實際的值。
正因為如此,映射是沒有長度的,也沒有 key 的集合或 value 的集合的概念。
只有狀態變數(或者在 internal 函式中的對于存盤變數的參考)可以使用映射型別。。
映射不支持迭代,但可以在此之上實作一個這樣的資料結構。
3.10 基本型別之間的轉換
隱式轉換
如果一個運算子用在兩個不同型別的變數之間,那么編譯器將隱式地將其中一個型別轉換為另一個型別(不同型別之間的賦值也是一樣)。
一般來說,只要值型別之間的轉換在語意上行得通,而且轉換的程序中沒有資訊丟失,那么隱式轉換基本都是可以實作的: uint8 可以轉換成 uint16,int128 轉換成 int256,但 int8 不能轉換成 uint256 (因為 uint256 不能涵蓋某些值,例如,-1)。
更進一步來說,無符號整型可以轉換成跟它大小相等或更大的位元組型別,但反之不能。
任何可以轉換成 uint160 的型別都可以轉換成 address 型別。
顯式轉換
如果某些情況下編譯器不支持隱式轉換,但是你很清楚你要做什么,這種情況可以考慮顯式轉換。 注意這可能會發生一些無法預料的后果,因此一定要進行測驗,確保結果是你想要的! 下面的示例是將一個 int8 型別的負數轉換成 uint:
int8 y = -3;
uint x = uint(y);
這段代碼的最后,x 的值將是 0xfffff..fd (64 個 16 進制字符),因為這是 -3 的 256 位補碼形式。
如果一個型別顯式轉換成更小的型別,相應的高位將被舍棄
uint32 a = 0x12345678;
uint16 b = uint16(a); // 此時 b 的值是 0x5678
型別推斷
為了方便起見,沒有必要每次都精確指定一個變數的型別,編譯器會根據分配該變數的第一個運算式的型別自動推斷該變數的型別
uint24 x = 0x123;
var y = x;
這里 y 的型別將是 uint24。不能對函式引數或者回傳引數使用 var。
uj5u.com熱心網友回復:
四、單元和全域變數
4.1 時間單位
秒是預設時間單位,在時間單位之間,數字后面帶有 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
由于閏秒造成的每年不都是 365 天、每天不都是 24 小時 leap seconds,所以如果你要使用這些單位計算日期和時間,請注意這個問題。因為閏秒是無法預測的,所以需要借助外部的預言機(oracle,是一種鏈外資料服務,譯者注)來對一個確定的日期代碼庫進行時間矯正。
years 后綴已經不推薦使用了,因為從 0.5.0 版本開始將不再支持。
這些后綴不能直接用在變數后邊。如果想用時間單位(例如 days)來將輸入變數換算為時間,你可以用如下方式來完成:
function f(uint start, uint daysAfter) public {
if (now >= start + daysAfter * 1 days) {
// ...
}
}
4.2 區塊和交易屬性
block.blockhash(uint blockNumber) returns (bytes32):指定區塊的區塊哈希——僅可用于最新的 256 個區塊且不包括當前區塊;而 blocks 從 0.4.22
版本開始已經不推薦使用,由 blockhash(uint blockNumber) 代替
block.coinbase (address): 挖出當前區塊的礦工地址
block.difficulty (uint): 當前區塊難度
block.gaslimit (uint): 當前區塊 gas 限額
block.number (uint): 當前區塊號
block.timestamp (uint): 自 unix epoch 起始當前區塊以秒計的時間戳
gasleft() returns (uint256):剩余的 gas
msg.data (bytes): 完整的 calldata
msg.gas (uint): 剩余 gas - 自 0.4.21 版本開始已經不推薦使用,由 gesleft() 代替
msg.sender (address): 訊息發送者(當前呼叫)
msg.sig (bytes4): calldata 的前 4 位元組(也就是函式識別符號)
msg.value (uint): 隨訊息發送的 wei 的數量
now (uint): 目前區塊時間戳(block.timestamp)
tx.gasprice (uint): 交易的 gas 價格
tx.origin (address): 交易發起者(完全的呼叫鏈)
```對于每一個**外部函式**呼叫,包括 msg.sender 和 msg.value 在內所有 msg 成員的值都會變化。這里包括對庫函式的呼叫。```
<font color=#FF0000>注意:</font>不要依賴 block.timestamp、 now 和 blockhash 產生亂數,除非你知道自己在做什么。
時間戳和區塊哈希在一定程度上都可能受到挖礦礦工影響。例如,挖礦社區中的惡意礦工可以用某個給定的哈希來運行賭場合約的 payout 函式,而如果他們沒收到錢,還可以用一個不同的哈希重新嘗試。
當前區塊的時間戳必須嚴格大于最后一個區塊的時間戳,但這里唯一能確保的只是它會是在權威鏈上的兩個連續區塊的時間戳之間的數值。
4.3 ABI 編碼函式
abi.encode(...) returns (bytes): ABI - 對給定引數進行編碼
abi.encodePacked(...) returns (bytes):對給定引數執行 緊打包編碼
abi.encodeWithSelector(bytes4 selector, ...) returns (bytes): ABI - 對給定引數進行編碼,并以給定的函式選擇器作為起始的 4 位元組資料一起回傳
abi.encodeWithSignature(string signature, ...) returns (bytes):等價于 abi.encodeWithSelector(bytes4(keccak256(signature), ...)
這些編碼函式可以用來建構式呼叫資料,而不用實際進行呼叫。此外,keccak256(abi.encodePacked(a, b)) 是更準確的方法來計算在未來版本不推薦使用的 keccak256(a, b)。
4.4 錯誤處理
assert(bool condition):
如果條件不滿足,則使當前交易沒有效果 — 用于檢查內部錯誤。
require(bool condition):
如果條件不滿足則撤銷狀態更改 - 用于檢查由輸入或者外部組件引起的錯誤。
require(bool condition, string message):
如果條件不滿足則撤銷狀態更改 - 用于檢查由輸入或者外部組件引起的錯誤,可以同時提供一個錯誤訊息。
revert():
終止運行并撤銷狀態更改。
revert(string reason):
終止運行并撤銷狀態更改,可以同時提供一個解釋性的字串。
錯誤型別:
JSONError: JSON輸入不符合所需格式,例如,輸入不是JSON物件,不支持的語言等。
IOError: IO和匯入處理錯誤,例如,在提供的源里包含無法決議的URL或哈希值不匹配。
ParserError: 源代碼不符合語言規則。
DocstringParsingError: 注釋塊中的NatSpec標簽無法決議。
SyntaxError: 語法錯誤,例如 continue 在 for 循環外部使用。
DeclarationError: 無效的,無法決議的或沖突的識別符號名稱 比如 Identifier not found。
TypeError: 型別系統內的錯誤,例如無效型別轉換,無效賦值等。
UnimplementedFeatureError: 編譯器當前不支持該功能,但預計將在未來的版本中支持。
InternalCompilerError: 在編譯器中觸發的內部錯誤——應將此報告為一個issue。
Exception: 編譯期間的未知失敗——應將此報告為一個issue。
CompilerError: 編譯器堆疊的無效使用——應將此報告為一個issue。
FatalError: 未正確處理致命錯誤——應將此報告為一個issue。
Warning: 警告,不會停止編譯,但應盡可能處理。
4.5 數學和密碼學函式
addmod(uint x, uint y, uint k) returns (uint)
計算 (x + y) % k,加法會在任意精度下執行,并且加法的結果即使超過 2**256 也不會被截取。從 0.5.0 版本的編譯器開始會加入對 k != 0 的校驗(assert)。
mulmod(uint x, uint y, uint k) returns (uint)
計算 (x * y) % k,乘法會在任意精度下執行,并且乘法的結果即使超過 2**256 也不會被截取。從 0.5.0 版本的編譯器開始會加入對 k != 0 的校驗(assert)。
keccak256(...) returns (bytes32)
計算 (tightly packed) arguments 的 Ethereum-SHA-3 (Keccak-256)哈希。
sha256(...) returns (bytes32)
計算 (tightly packed) arguments 的 SHA-256 哈希。
sha3(...) returns (bytes32)
等價于 keccak256。
ripemd160(...) returns (bytes20)
計算 (tightly packed) arguments 的 RIPEMD-160 哈希。
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
利用橢圓曲線簽名恢復與公鑰相關的地址,錯誤回傳零值。
上文中的“tightly packed”是指不會對引數值進行 padding 處理(就是說所有引數值的位元組碼是連續存放的,譯者注),這意味著下邊這些呼叫都是等價的:
keccak256("ab", "c") keccak256("abc") keccak256(0x616263) keccak256(6382179) keccak256(97, 98, 99)
如果需要 padding,可以使用顯式型別轉換:
keccak256("\x00\x12") 和 keccak256(uint16(0x12)) 是一樣的。
請注意,常量值會使用存盤它們所需要的最少位元組數進行打包。例如:
keccak256(0) == keccak256(uint8(0)),
keccak256(0x12345678) == keccak256(uint32(0x12345678))。
4.6 地址相關
<address>.balance (uint256)
以 Wei 為單位的 地址型別 的余額。
<address>.transfer(uint256 amount)
向 地址型別 發送數量為 amount 的 Wei,失敗時拋出例外,發送 2300 gas 的礦工費,不可調節。
<address>.send(uint256 amount) returns (bool)
向 地址型別 發送數量為 amount 的 Wei,失敗時回傳 false,發送 2300 gas 的礦工費用,不可調節。
<address>.call(...) returns (bool)
發出低級函式 CALL,失敗時回傳 false,發送所有可用 gas,可調節。
<address>.callcode(...) returns (bool)
發出低級函式 CALLCODE,失敗時回傳 false,發送所有可用 gas,可調節。
<address>.delegatecall(...) returns (bool)
發出低級函式 DELEGATECALL,失敗時回傳 false,發送所有可用 gas,可調節。
警告:使用 send 有很多危險:如果呼叫堆疊深度已經達到 1024(這總是可以由呼叫者所強制指定),轉賬會失敗;并且如果接收者用光了 gas,轉賬同樣會失敗。為了保證以太幣轉賬安全,總是檢查 send 的回傳值,利用 transfer 或者下面更好的方式: 用這種接收者取回錢的模式。
不鼓勵使用 callcode,并且將來它會被移除。
4.7 合約相關
this (current contract's type)
當前合約,可以明確轉換為 地址型別。
selfdestruct(address recipient)
銷毀合約,并把余額發送到指定 地址型別。
suicide(address recipient)
與 selfdestruct 等價,但已不推薦使用。
此外,當前合約內的所有函式都可以被直接呼叫,包括當前函式。
————————————————
著作權宣告:本文作者為「Li_Yu_Qing」
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/30148.html
標籤:區塊鏈技術
上一篇:智能合約
