您好,登錄后才能下訂單哦!
上一篇:智能合約編程語(yǔ)言-solidity快速入門(上)
在介紹區(qū)塊及交易屬性之前,我們需要先知道solidity中自帶了一些全局變量和函數(shù),這些變量和函數(shù)可以認(rèn)為是solidity提供的API,這些 API 主要表現(xiàn)為Solidity 內(nèi)置的特殊的變量及函數(shù),它們存在于全局命名空間里,主要分為以下幾類:
我們?cè)诰帉懼悄芎霞s的時(shí)候就可以通過這些API來(lái)獲取區(qū)塊和交易的屬性(Block And Transaction Properties),簡(jiǎn)單來(lái)說(shuō)這些API主要用來(lái)提供一些區(qū)塊鏈當(dāng)前的信息,下表列出常用的一些API:
API | 描述 |
---|---|
blockhash(uint blockNumber) returns (bytes32) | 返回給定區(qū)塊號(hào)的哈希值,只支持最近256個(gè)區(qū)塊,且不包含當(dāng)前區(qū)塊 |
block.coinbase (address) | 獲取當(dāng)前塊礦工的地址 |
block.difficulty (uint) | 獲取當(dāng)前塊的難度 |
block.gaslimit (uint) | 獲取當(dāng)前塊的gaslimit |
block.number (uint) | 獲取當(dāng)前區(qū)塊的塊號(hào) |
block.timestamp (uint) | 獲取當(dāng)前塊的Unix時(shí)間戳(從1970/1/1 00:00:00 UTC開始所經(jīng)過的秒數(shù)) |
gasleft() (uint256) | 獲取剩余gas |
msg.data (bytes) | 獲取完整的調(diào)用數(shù)據(jù)(calldata) |
msg.gas (uint) | 獲取當(dāng)前還剩的gas(已棄用) |
msg.sender (address) | 獲取當(dāng)前調(diào)用發(fā)起人的地址 |
msg.sig (bytes4) | 獲取調(diào)用數(shù)據(jù)(calldata)的前四個(gè)字節(jié)(例如為:函數(shù)標(biāo)識(shí)符) |
msg.value (uint) | 獲取這個(gè)消息所附帶的以太幣,單位為wei |
now (uint) | 獲取當(dāng)前塊的時(shí)間戳(實(shí)際上是block.timestamp的別名) |
tx.gasprice (uint) | 獲取交易的gas價(jià)格 |
tx.origin (address) | 獲取交易的發(fā)送者(全調(diào)用鏈) |
注意:
msg的所有成員值,如msg.sender,msg.value的值可以因?yàn)槊恳淮瓮獠亢瘮?shù)調(diào)用,或庫(kù)函數(shù)調(diào)用發(fā)生變化(因?yàn)閙sg就是和調(diào)用相關(guān)的全局變量)。
不應(yīng)該依據(jù) block.timestamp, now 和 block.blockhash來(lái)產(chǎn)生一個(gè)隨機(jī)數(shù)(除非你確實(shí)需要這樣做),這幾個(gè)值在一定程度上被礦工影響(比如在×××合約里,不誠(chéng)實(shí)的礦工可能會(huì)重試去選擇一個(gè)對(duì)自己有利的hash)。
對(duì)于同一個(gè)鏈上連續(xù)的區(qū)塊來(lái)說(shuō),當(dāng)前區(qū)塊的時(shí)間戳(timestamp)總是會(huì)大于上一個(gè)區(qū)塊的時(shí)間戳。為了可擴(kuò)展性的原因,你只能查最近256個(gè)塊,所有其它的將返回0.
接下來(lái)使用代碼演示一下常用的全局變量:
pragma solidity ^0.4.17;
contract SolidityAPI {
function getSender() public constant returns(address) {
// 獲取當(dāng)前調(diào)用發(fā)起人的地址
return msg.sender;
}
function getValue() public constant returns(uint) {
// 獲取這個(gè)消息所附帶的以太幣,單位為wei
return msg.value;
}
function getBlockCoinbase() public constant returns(address) {
// 獲取當(dāng)前塊礦工的地址
return block.coinbase;
}
function getBlockDifficulty() public constant returns(uint) {
// 獲取當(dāng)前塊的難度
return block.difficulty;
}
function getBlockNumber() public constant returns(uint) {
// 獲取當(dāng)前區(qū)塊的塊號(hào)
return block.number;
}
function getBlockTimestamp() public constant returns(uint) {
// 獲取當(dāng)前塊的Unix時(shí)間戳
return block.timestamp;
}
function getNow() public constant returns(uint) {
// 獲取當(dāng)前塊的時(shí)間戳
return now;
}
function getGasprice() public constant returns(uint) {
// 獲取交易的gas價(jià)格
return tx.gasprice;
}
}
ABI全稱Application Binary Interface,翻譯過來(lái)就是:應(yīng)用程序二進(jìn)制接口,是調(diào)用智能合約函數(shù)以及合約之間函數(shù)調(diào)用的消息編碼格式定義,也可以理解為智能合約函數(shù)調(diào)用的接口說(shuō)明。類似Webservice里的SOAP協(xié)議一樣;也就是定義操作函數(shù)簽名,參數(shù)編碼,返回結(jié)果編碼等。
簡(jiǎn)單來(lái)說(shuō)從外部施加給以太坊的行為都稱之為向以太坊網(wǎng)絡(luò)提交了一個(gè)交易, 調(diào)用合約函數(shù)其實(shí)是向合約地址(賬戶)提交了一個(gè)交易,這個(gè)交易有一個(gè)附加數(shù)據(jù),這個(gè)附加的數(shù)據(jù)就是ABI的編碼數(shù)據(jù)。因此要想和合約交互,就離不開ABI數(shù)據(jù)。
solidity 提供了以下函數(shù),用來(lái)直接得到ABI編碼信息,如下表:
函數(shù) | 描述 |
---|---|
abi.encode(...) returns (bytes) | 計(jì)算參數(shù)的ABI編碼 |
abi.encodePacked(...) returns (bytes) | 計(jì)算參數(shù)的緊密打包編碼 |
abi. encodeWithSelector(bytes4 selector, ...) returns (bytes) | 計(jì)算函數(shù)選擇器和參數(shù)的ABI編碼 |
abi.encodeWithSignature(string signature, ...) returns (bytes) | 等價(jià)于 abi.encodeWithSelector(bytes4(keccak256(signature), ...) |
通過ABI編碼函數(shù)可以在不用調(diào)用函數(shù)的情況下,獲得ABI編碼值,下面通過一段代碼來(lái)看看這些方式的使用:
pragma solidity ^0.4.24;
contract testABI {
uint storedData;
function set(uint x) public {
storedData = x;
}
function abiEncode() public constant returns (bytes) {
// 計(jì)算 1 的ABI編碼
abi.encode(1);
//計(jì)算函數(shù)set(uint256) 及參數(shù)1 的ABI 編碼
return abi.encodeWithSignature("set(uint256)", 1);
}
}
在很多編程語(yǔ)言中都具有錯(cuò)誤處理機(jī)制,在solidity中自然也不例外,solidity最開始的錯(cuò)誤處理方式是使用throw以及if … throw,后來(lái)因?yàn)檫@種方式會(huì)消耗掉所有剩余的gas,所以目前throw的方式已經(jīng)被棄用,改為使用以下函數(shù)進(jìn)行錯(cuò)誤處理:
函數(shù) | 描述 |
---|---|
assert(bool condition) | 用于判斷內(nèi)部錯(cuò)誤,條件不滿足時(shí)拋出異常 |
require(bool condition) | 用于判斷輸入或外部組件錯(cuò)誤,條件不滿足時(shí)拋出異常 |
require(bool condition, string message) | 同上,多了一個(gè)錯(cuò)誤信息 |
revert() | 終止執(zhí)行并還原改變的狀態(tài) |
revert(string reason) | 同上,提供一個(gè)錯(cuò)誤信息 |
solidity中的錯(cuò)誤處理機(jī)制和其他大多數(shù)編程語(yǔ)言不一樣,solidity是通過回退狀態(tài)來(lái)進(jìn)行錯(cuò)誤處理的,就像數(shù)據(jù)庫(kù)事務(wù)一樣,也就是說(shuō)solidity沒有try-catch這種捕獲異常的方式。在發(fā)生異常時(shí)solidity會(huì)撤銷當(dāng)前調(diào)用(及其所有子調(diào)用)所改變的狀態(tài),同時(shí)給調(diào)用者返回一個(gè)錯(cuò)誤標(biāo)識(shí)。但是消耗的gas不會(huì)回退,會(huì)正常消耗掉。
solidity之所以使用這種方式處理錯(cuò)誤,是因?yàn)閰^(qū)塊鏈就類似于全球共享的分布式事務(wù)性數(shù)據(jù)庫(kù)(公鏈)。全球共享意味著參與這個(gè)網(wǎng)絡(luò)的每一個(gè)人都可以讀寫其中的數(shù)據(jù),如果沒有這種事務(wù)一般的錯(cuò)誤處理機(jī)制就會(huì)導(dǎo)致一些操作成功一些操作失敗,所帶來(lái)的結(jié)果就是數(shù)據(jù)的混亂、不一致。所以使用這種事務(wù)一般的錯(cuò)誤處理機(jī)制可以保證一組調(diào)用及其子調(diào)用要么成功要么失敗回滾,就像啥事都沒有發(fā)生一樣,solidity錯(cuò)誤處理就是要保證每次調(diào)用都是具有事務(wù)性的。
大概了解了solidity的錯(cuò)誤處理機(jī)制后,我們來(lái)看看如何在solidity中進(jìn)行錯(cuò)誤處理。從上表中可以看到solidity提供了兩個(gè)函數(shù)assert和require來(lái)進(jìn)行條件檢查,如果條件不滿足則拋出異常。assert函數(shù)通常用來(lái)檢查(測(cè)試)內(nèi)部錯(cuò)誤,而require函數(shù)來(lái)檢查輸入變量或合同狀態(tài)變量是否滿足條件以及驗(yàn)證調(diào)用外部合約返回值。
另外,如果我們正確使用assert,使用一些solidity分析工具就可以幫我們分析出智能合約中的錯(cuò)誤,幫助我們發(fā)現(xiàn)合約中有邏輯錯(cuò)誤的bug。
assert和require兩個(gè)函數(shù)實(shí)際上也就對(duì)應(yīng)著兩種類型的異常 ,即assert類型異常及require類型異常。當(dāng)發(fā)生assert類型異常時(shí),會(huì)消耗掉所有提供的gas,而require類型異常則不會(huì)消耗。當(dāng)發(fā)生require類型的異常時(shí),Solidity會(huì)執(zhí)行一個(gè)回退操作(指令0xfd)。當(dāng)發(fā)生assert類型的異常時(shí),Solidity會(huì)執(zhí)行一個(gè)無(wú)效操作(指令0xfe)。
在上述的兩種情況下,EVM都會(huì)撤回所有的狀態(tài)改變。是因?yàn)槠谕慕Y(jié)果沒有發(fā)生,就沒法繼續(xù)安全執(zhí)行。必須保證交易的原子性(一致性,要么全部執(zhí)行,要么一點(diǎn)改變都沒有,不能只改變一部分),所以需要撤銷所有操作,讓整個(gè)交易沒有任何影響。
自動(dòng)產(chǎn)生assert類型異常的場(chǎng)景:
自動(dòng)產(chǎn)生require類型異常的場(chǎng)景:
除了可以兩個(gè)函數(shù)assert和require來(lái)進(jìn)行條件檢查,另外還有兩種方式來(lái)觸發(fā)異常:
當(dāng)子調(diào)用中發(fā)生異常時(shí),異常會(huì)自動(dòng)向上“冒泡”。 不過也有一些例外:send,和底層的函數(shù)調(diào)用call, delegatecall,callcode,當(dāng)發(fā)生異常時(shí),這些函數(shù)返回false。
注意:在一個(gè)不存在的地址上調(diào)用底層的函數(shù)call,delegatecall,callcode 也會(huì)返回成功,所以我們?cè)谶M(jìn)行調(diào)用時(shí),應(yīng)該總是優(yōu)先進(jìn)行函數(shù)存在性檢查。
在下面通過一個(gè)示例來(lái)說(shuō)明如何使用require來(lái)檢查輸入條件,代碼中使用了require函數(shù)檢查msg.value的值是否為偶數(shù),此時(shí)我們?cè)O(shè)置value值為2,可以正常的運(yùn)行sendHalf函數(shù):
詳細(xì)的日志如下:
接著我們測(cè)試異常的情況,將value改成1,即不能被2整除的數(shù),執(zhí)行sendHalf函數(shù)后,控制臺(tái)輸出的錯(cuò)誤日志如下,從錯(cuò)誤日志中我們可以看到此次交易被reverted到一個(gè)初始的狀態(tài):
然后我們?cè)賮?lái)看一個(gè)示例,使用assert函數(shù)檢查內(nèi)部錯(cuò)誤:
pragma solidity ^0.4.20;
contract Sharer {
function sendHalf(address addr) public payable returns(uint balance){
// 僅允許偶數(shù)
require(msg.value % 2 == 0);
uint balanceBeforeTransfer = this.balance;
addr.transfer(msg.value / 2);
// 檢查當(dāng)前的balance是否為轉(zhuǎn)移之前的一半,不符合條件則會(huì)拋出異常
assert(this.balance == balanceBeforeTransfer - msg.value / 2);
return this.balance;
}
}
本小節(jié)我們來(lái)介紹一下solidity中的函數(shù)參數(shù),與其他編程語(yǔ)言一樣,solidity 函數(shù)可以提供參數(shù)作為輸入并且函數(shù)類型本身也可以作為參數(shù),與JavaScript和C不同的是,solidity還可以返回任意數(shù)量的返回值作為輸出。
1.輸入?yún)?shù),輸入?yún)?shù)的聲明方式與變量相同, 未使用的參數(shù)可以省略變量名稱。假設(shè)我們希望合約中的某個(gè)函數(shù)被外部調(diào)用時(shí),傳入兩個(gè)整型參數(shù),那么就可以這樣寫:
pragma solidity ^0.4.16;
contract Test {
function inputParam(uint a, uint b) public {
// ...
}
}
2.輸出參數(shù),輸出參數(shù)的聲明和輸入?yún)?shù)一樣,只不過它接在returns之后,也就是函數(shù)的返回值,只不過在solidity中函數(shù)的返回值可以像輸入?yún)?shù)一樣被處理。假設(shè)我們希望返回兩個(gè)結(jié)果,兩個(gè)給定整數(shù)的和以及積,可以這樣寫:
pragma solidity ^0.4.16;
contract Test {
function testOutput(uint a, uint b) public returns (uint sum, uint mul) {
sum = a + b;
mul = a * b;
}
}
可以省略輸出參數(shù)的名稱,也可以使用return語(yǔ)句指定輸出值,return可以返回多個(gè)值。(當(dāng)返回一個(gè)沒有賦值的參數(shù)時(shí),默認(rèn)為0)
輸入?yún)?shù)和輸出參數(shù)可以在函數(shù)內(nèi)表達(dá)式中使用,也可以作為被賦值的對(duì)象, 如下示例:
contract Test {
function testOutput(uint a, uint b) public returns (uint c) {
a = 1;
b = 2;
c = 3;
}
}
3.命名參數(shù),調(diào)用某個(gè)函數(shù)時(shí)傳遞的參數(shù),可以通過指定名稱的方式傳遞,使用花括號(hào){}包起來(lái),參數(shù)順序任意,但參數(shù)的類型和數(shù)量要與定義一致,這與Python中的關(guān)鍵字參數(shù)一樣的。如:
pragma solidity ^0.4.0;
contract Test {
function a(uint key, uint value) public {
// ...
}
function b() public {
// 命名參數(shù)
a({value: 2, key: 3});
}
}
4.參數(shù)解構(gòu),當(dāng)一個(gè)函數(shù)有多個(gè)輸出參數(shù)時(shí),可以使用元組(tuple)來(lái)返回多個(gè)值。元組(tuple)是一個(gè)數(shù)量固定,類型可以不同的元素組成的一個(gè)列表(用小括號(hào)表示),使用return (v0, v1, …, vn) 語(yǔ)句,就可以返回多個(gè)值,返回值的數(shù)量需要和輸出參數(shù)聲明的數(shù)量一致。當(dāng)函數(shù)返回多個(gè)值時(shí),可以使用多個(gè)變量去接收,此時(shí)元組內(nèi)的元素就會(huì)同時(shí)賦值給多個(gè)變量,這個(gè)過程就稱之為參數(shù)解構(gòu)。如下示例:
function a() public pure returns (uint, bool, uint) {
// 使用元組返回多個(gè)值
return (7, true, 2);
}
function b() public {
uint x;
bool y;
uint z;
// 使用元組給多個(gè)變量賦值
(x, y , z) = a();
}
solidity 的流程控制語(yǔ)句與其他大多數(shù)語(yǔ)言一致,擁有if、else、while、do、for、break、continue、return以及三元表達(dá)式 ? :等流程控制語(yǔ)句,這些語(yǔ)句在solidity中的含義與其他語(yǔ)言是一致的這里就不再詳細(xì)贅述了,不過要注意的是solidity中沒有switch和goto語(yǔ)句。
以下使用一個(gè)簡(jiǎn)單的例子演示一下這些流程控制語(yǔ)句的使用方式,代碼如下:
pragma solidity ^0.4.20;
contract Test {
function testWhile() public constant returns(uint){
uint i = 0;
uint sumOfAdd = 0;
while(true) {
i++;
if (i > 10){
break;
}
if (i % 2 == 0) {
continue;
} else {
sumOfAdd += i;
}
}
sumOfAdd = sumOfAdd > 20 ? sumOfAdd + 10 : sumOfAdd;
return sumOfAdd;
}
function testForLoop() public constant returns(uint) {
uint sum = 0;
for (uint i = 0; i < 10; i++) {
sum +=i;
}
return sum;
}
}
大多數(shù)的語(yǔ)言都會(huì)有權(quán)限修飾符,盡管它們都不盡相同,在 solidity 中有public、private、external以及internal四種權(quán)限修飾符,接下來(lái)我們看看四種權(quán)限修飾符的作用。
1.public
public所修飾的函數(shù)稱為公開函數(shù),是合約接口的一部分,可以通過內(nèi)部,或者消息來(lái)進(jìn)行調(diào)用。對(duì)于public類型的狀態(tài)變量,會(huì)自動(dòng)創(chuàng)建一個(gè)訪問器,這個(gè)訪問器其實(shí)是一個(gè)函數(shù)。solidity 中的函數(shù)默認(rèn)是public的
我們來(lái)看一個(gè)公開函數(shù)的例子,在remix上我們可以看到并執(zhí)行公開的函數(shù):
2.private
表示私有的函數(shù)和狀態(tài)變量,僅在當(dāng)前合約中可以訪問,在繼承的合約內(nèi)不可以訪問,也不可以被外部訪問
例如我們來(lái)寫一個(gè)私有函數(shù),并且進(jìn)行部署,此時(shí)會(huì)發(fā)現(xiàn)在外部是看不到這個(gè)函數(shù)的:
3.external
表示外部函數(shù),與public修飾的函數(shù)有些類似,也是合約接口的一部分,但只能使用消息調(diào)用,不可以直接通過內(nèi)部調(diào)用,值得注意的是external函數(shù)消耗的gas比public函數(shù)要少,所以當(dāng)我們一個(gè)函數(shù)只能被外部調(diào)用時(shí)盡量使用external修飾
同樣的,我們來(lái)看一個(gè)簡(jiǎn)單的例子,代碼如下:
4.internal
使用此修飾符修飾的函數(shù)和狀態(tài)變量只能通過內(nèi)部訪問,例如在當(dāng)前合約中調(diào)用,或繼承的合約中調(diào)用。solidity 中的狀態(tài)變量默認(rèn)是internal的
如下示例:
在上一小節(jié)中,我們介紹了 solidity 中的權(quán)限修飾符,其中涉及到了內(nèi)部函數(shù)調(diào)用和外部函數(shù)調(diào)用的概念,所以這一節(jié)我們進(jìn)一步介紹這兩個(gè)概念。
1.內(nèi)部函數(shù)調(diào)用(Internal Function Calls)
內(nèi)部調(diào)用,不會(huì)創(chuàng)建一個(gè)EVM消息調(diào)用。而是直接調(diào)用當(dāng)前合約的函數(shù),也可以遞歸調(diào)用。
如下面這個(gè)的例子:
pragma solidity ^0.4.20;
contract Test {
function a(uint a) public pure returns (uint ret) {
// 直接調(diào)用
return b();
}
function b() internal pure returns (uint ret) {
// 直接調(diào)用及遞歸調(diào)用
return a(7) + b();
}
}
這些函數(shù)調(diào)用被轉(zhuǎn)換為EVM內(nèi)部的簡(jiǎn)單指令跳轉(zhuǎn)(jumps)。 這樣帶來(lái)的一個(gè)好處是,當(dāng)前的內(nèi)存不會(huì)被回收。在一個(gè)內(nèi)部調(diào)用時(shí)傳遞一個(gè)內(nèi)存型引用效率將非常高的。當(dāng)然,僅僅是同一個(gè)合約的函數(shù)之間才可通過內(nèi)部的方式進(jìn)行調(diào)用。
2.外部函數(shù)調(diào)用(External Function Calls)
外部調(diào)用,會(huì)創(chuàng)建EVM消息調(diào)用。表達(dá)式
this.sum(8);
和number.add(2);
(這里的number是一個(gè)合約實(shí)例)是外部調(diào)用函數(shù)的方式,它會(huì)發(fā)起一個(gè)消息調(diào)用,而不是EVM的指令跳轉(zhuǎn)。需要注意的是,在合約的構(gòu)造器中,不能使用this調(diào)用函數(shù),因?yàn)楫?dāng)前合約還沒有創(chuàng)建完成
其它合約的函數(shù)必須通過外部的方式調(diào)用。對(duì)于一個(gè)外部調(diào)用,所有函數(shù)的參數(shù)必須要拷貝到內(nèi)存中。當(dāng)調(diào)用其它合約的函數(shù)時(shí),可以通過選項(xiàng).value()
,和.gas()
來(lái)分別指定要發(fā)送的以太幣(以wei為單位)和gas值。如下示例:
pragma solidity ^0.4.20;
contract InfoFeed {
// 必須使用`payable`關(guān)鍵字修飾,否則不能通過`value()`函數(shù)來(lái)接收以太幣
function info() public payable returns (uint ret) {
return 42;
}
}
contract Consumer {
InfoFeed feed;
function setFeed(address addr) public {
// 這句代碼進(jìn)行了一個(gè)顯示的類型轉(zhuǎn)換,表示給定的地址是合約`InfoFeed`類型,這里并不會(huì)執(zhí)行構(gòu)造器的初始化。
// 在進(jìn)行顯式的類型強(qiáng)制轉(zhuǎn)換時(shí)需要非常小心,不要調(diào)用一個(gè)未知類型的合約函數(shù)
feed = InfoFeed(addr);
}
function callFeed() public {
// 附加以太幣及gas來(lái)調(diào)用info,注意這里僅僅是對(duì)發(fā)送的以太幣和gas值進(jìn)行了設(shè)置,真正的調(diào)用是后面的括號(hào)()
feed.info.value(10).gas(800)();
}
}
注:調(diào)用callFeed
時(shí),需要預(yù)先存入一定量的以太幣,不然可能會(huì)因余額不足報(bào)錯(cuò)。
在與外部合約交互時(shí)需要注意的事項(xiàng):
如果我們不知道被調(diào)用的合約源代碼,那么和這些合約的交互就會(huì)有潛在的風(fēng)險(xiǎn),即便被調(diào)用的合約繼承自一個(gè)已知的父合約(因?yàn)槔^承僅僅要求正確實(shí)現(xiàn)接口,而不關(guān)注實(shí)現(xiàn)的內(nèi)容)。因?yàn)楹瓦@些合約交互時(shí),就相當(dāng)于把自己控制權(quán)交給被調(diào)用的合約,對(duì)方幾乎可以利用它做任何事。此外, 被調(diào)用的合約可以改變調(diào)用合約的狀態(tài)變量,所以在編寫函數(shù)時(shí)需要注意可重入性漏洞問題
solidity 有以下四種函數(shù):
1.構(gòu)造函數(shù):
構(gòu)造函數(shù)在合約創(chuàng)建的時(shí)候運(yùn)行,我們通常會(huì)在構(gòu)造函數(shù)做一些初始化的操作,構(gòu)造函數(shù)也是可以有參數(shù)的
如下示例:
2.視圖函數(shù)(constant / view):
使用 constant 或者 view 關(guān)鍵字修飾的函數(shù)就是視圖函數(shù),視圖函數(shù)不會(huì)修改合約的狀態(tài)變量。constant 與 view 是等價(jià)的,constant 是view 的別名,constant在計(jì)劃Solidity 0.5.0版本之后會(huì)棄用(constant這個(gè)詞有歧義,view 也更能表達(dá)返回值可視),所以在新版的solidity中推薦優(yōu)先使用view
視圖函數(shù)有個(gè)特點(diǎn)就是在remix執(zhí)行后可以直接看到返回值:
一個(gè)函數(shù)如果它不修改狀態(tài)變量,應(yīng)該聲明為視圖函數(shù),以下幾種情況被認(rèn)為修改了狀態(tài)變量:
3.純函數(shù)(pure):
純函數(shù)是使用 pure 關(guān)鍵字修飾的函數(shù),純函數(shù)不會(huì)讀取狀態(tài)變量,也不會(huì)修改狀態(tài)變量
如下示例:
以下幾種情況被認(rèn)為是讀取了狀態(tài):
4.回退函數(shù):
回退函數(shù)實(shí)際上是一個(gè)匿名函數(shù),并且是一個(gè)只能被動(dòng)調(diào)用的函數(shù),一個(gè)合約中只能有一個(gè)回退函數(shù)。通常當(dāng)我們的一個(gè)智能合約需要接收以太幣的時(shí),就需要實(shí)現(xiàn)回退函數(shù),而且回退函數(shù)的實(shí)現(xiàn)應(yīng)該盡量的簡(jiǎn)單
如下示例:
如果沒有實(shí)現(xiàn)回退函數(shù),其他合約是無(wú)法往該合約發(fā)送以太幣的:
回退函數(shù)會(huì)在以下情況被調(diào)用:
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。