函數(shù)調(diào)用

2022-05-12 17:02 更新

內(nèi)部函數(shù)調(diào)用

當(dāng)前合約的函數(shù)可以直接(“內(nèi)部”)調(diào)用,也可以遞歸調(diào)用,如以下無意義的示例所示:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

// This will report a warning
contract C {
    function g(uint a) public pure returns (uint ret) { return a + f(); }
    function f() internal pure returns (uint ret) { return g(7) + f(); }
}

這些函數(shù)調(diào)用被轉(zhuǎn)換為 EVM 內(nèi)的簡單跳轉(zhuǎn)。這具有不清除當(dāng)前內(nèi)存的效果,即將內(nèi)存引用傳遞給內(nèi)部調(diào)用的函數(shù)非常有效。只能在內(nèi)部調(diào)用同一合約實(shí)例的函數(shù)。

您仍然應(yīng)該避免過度遞歸,因?yàn)槊總€(gè)內(nèi)部函數(shù)調(diào)用至少使用一個(gè)堆棧槽并且只有 1024 個(gè)可用槽。

外部函數(shù)調(diào)用

也可以使用this.g(8);andc.g(2);表示法調(diào)用函數(shù),其中 c是合約實(shí)例,g是屬于 的函數(shù)c。通過任何一種方式調(diào)用函數(shù)g都會(huì)導(dǎo)致它被“外部”調(diào)用,使用消息調(diào)用而不是直接通過跳轉(zhuǎn)。請(qǐng)注意,函數(shù)調(diào)用this不能在構(gòu)造函數(shù)中使用,因?yàn)閷?shí)際的合約尚未創(chuàng)建。

其他合約的函數(shù)必須在外部調(diào)用。對(duì)于外部調(diào)用,所有函數(shù)參數(shù)都必須復(fù)制到內(nèi)存中。

筆記

從一個(gè)合約到另一個(gè)合約的函數(shù)調(diào)用不會(huì)創(chuàng)建自己的交易,它是作為整個(gè)交易的一部分的消息調(diào)用。

在調(diào)用其他合約的函數(shù)時(shí),您可以通過特殊選項(xiàng)指定調(diào)用時(shí)發(fā)送的 Wei 或 Gas 數(shù)量。請(qǐng)注意,不鼓勵(lì)明確指定 gas 值,因?yàn)椴僮鞔a的 gas 成本可能會(huì)在未來發(fā)生變化。您發(fā)送給合約的任何 Wei 都會(huì)添加到該合約的總余額中:{value: 10, gas: 10000}

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;

contract InfoFeed {
    function info() public payable returns (uint ret) { return 42; }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(InfoFeed addr) public { feed = addr; }
    function callFeed() public { feed.info{value: 10, gas: 800}(); }
}

您需要將修飾符payableinfo函數(shù)一起使用,否則該value選項(xiàng)將不可用。

警告

請(qǐng)注意,僅在本地設(shè)置 函數(shù)調(diào)用的發(fā)送量和發(fā)送量,最后的括號(hào)執(zhí)行實(shí)際調(diào)用。so 不調(diào)用函數(shù)并且和設(shè)置丟失,只 執(zhí)行函數(shù)調(diào)用。feed.info{value: 10, gas: 800}valuegasfeed.info{value: 10, gas: 800}valuegasfeed.info{value: 10, gas: 800}()

由于 EVM 認(rèn)為對(duì)不存在的合約的調(diào)用總是成功的,Solidity 使用extcodesize操作碼檢查即將被調(diào)用的合約是否確實(shí)存在(它包含代碼),如果不存在則引發(fā)異常. 如果返回?cái)?shù)據(jù)將在調(diào)用后被解碼,則跳過此檢查,因此 ABI 解碼器將捕獲不存在合約的情況。

請(qǐng)注意,在對(duì)地址而不是合約實(shí)例進(jìn)行操作的低級(jí)調(diào)用的情況下,不會(huì)執(zhí)行此檢查。

筆記

對(duì)預(yù)編譯合約使用高級(jí)調(diào)用時(shí)要小心 ,因?yàn)榧词顾鼈儓?zhí)行代碼并且可以返回?cái)?shù)據(jù),編譯器也會(huì)根據(jù)上述邏輯認(rèn)為它們不存在。

如果被調(diào)用的合約本身拋出異常或耗盡gas,函數(shù)調(diào)用也會(huì)導(dǎo)致異常。

警告

與另一個(gè)合約的任何交互都會(huì)帶來潛在的危險(xiǎn),特別是如果事先不知道合約的源代碼。當(dāng)前的合約將控制權(quán)移交給被調(diào)用的合約,這可能會(huì)做任何事情。即使被調(diào)用的合約繼承自已知的父合約,也只需要繼承的合約有正確的接口即可。然而,合同的執(zhí)行可能是完全任意的,因此會(huì)造成危險(xiǎn)。此外,請(qǐng)做好準(zhǔn)備,以防它在第一次調(diào)用返回之前調(diào)用系統(tǒng)的其他合約,甚至返回調(diào)用合約。這意味著被調(diào)用合約可以通過其函數(shù)改變調(diào)用合約的狀態(tài)變量。以某種方式編寫函數(shù),例如,

筆記

在 Solidity 0.6.2 之前,指定值和氣體的推薦方法是使用f.value(x).gas(g)(). 這在 Solidity 0.6.2 中已被棄用,并且自 Solidity 0.7.0 起不再可行。

命名調(diào)用和匿名函數(shù)參數(shù)

函數(shù)調(diào)用參數(shù)可以按任何順序按名稱給出,如果它們被包含在下面的示例中。參數(shù)列表的名稱必須與函數(shù)聲明中的參數(shù)列表一致,但可以是任意順序。{ }

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;

contract C {
    mapping(uint => uint) data;

    function f() public {
        set({value: 2, key: 3});
    }

    function set(uint key, uint value) public {
        data[key] = value;
    }

}

省略的函數(shù)參數(shù)名稱

未使用的參數(shù)(尤其是返回參數(shù))的名稱可以省略。這些參數(shù)仍將存在于堆棧中,但無法訪問。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract C {
    // omitted name for parameter
    function func(uint k, uint) public pure returns(uint) {
        return k;
    }
}
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)