1. 程式人生 > >Solidity 官方文件中文版(三)

Solidity 官方文件中文版(三)

函式呼叫(Function Calls)

內部函式呼叫(Internal Function Calls)

在當前的合約中,函式可以直接呼叫(內部呼叫方式),包括也可遞迴呼叫,來看一個簡單的示例:

contract C {
    function g(uint a) returns (uint ret) { return f(); }
    function f() returns (uint ret) { return g(7) + f(); }
}

這些函式呼叫在EVM中被翻譯成簡單的跳轉指令。這樣帶來的一個好處是,當前的記憶體不會被回收。所以在一個內部呼叫時傳遞一個記憶體型引用效率將非常高。當然,僅僅是同一個合約的函式之間才可通過內部的方式進行呼叫。

外部函式呼叫(External Function Calls)

表示式this.g(8);c.g(2)(這裡的c是一個合約例項)是外部呼叫函式的方式。實現上是通過一個訊息呼叫,而不是直接通過EVM的指令跳轉。需要注意的是,在合約的構造器中,不能使用this呼叫函式,因為當前合約還沒有建立完成。

其它合約的函式必須通過外部的方式呼叫。對於一個外部呼叫,所有函式的引數必須要拷貝到記憶體中。

當呼叫其它合約的函式時,可以通過選項.value(),和.gas()來分別指定,要傳送的ether量(以wei為單位),和gas值。

pragma solidity ^0.4.0;

contract InfoFeed {
    
    function
info() payable returns (uint ret)
{ return msg.value; } } contract Consumer { function deposit() payable returns (uint){ return msg.value; } function left() constant returns (uint){ return this.balance; } function callFeed(address addr)
returns (uint)
{ return InfoFeed(addr).info.value(1).gas(8000)(); } }

上面的程式碼中,我們首先呼叫deposit()Consumer合約存入一定量的ether。然後呼叫callFeed()通過value(1)的方式,向InfoFeed合約的info()函式傳送1ether。需要注意的是,如果不先充值,由於合約餘額為0,餘額不足會報錯Invalid opcode1

InfoFeed.info()函式,必須使用payable關鍵字,否則不能通過value()選項來接收ether

程式碼InfoFeed(addr)進行了一個顯示的型別轉換,聲明瞭我們確定知道給定的地址是InfoFeed型別。所以這裡並不會執行構造器的初始化。顯示的型別強制轉換,需要極度小心,不要嘗試呼叫一個你不知道型別的合約。

我們也可以使用function setFeed(InfoFeed _feed) { feed = _feed; }來直接進行賦值。.info.value(1).gas(8000)只是本地設定傳送的數額和gas值,真正執行呼叫的是其後的括號.info.value(1).gas(8000)()

如果被呼叫的合約不存在,或者是不包程式碼的帳戶,或呼叫的合約產生了異常,或者gas不足,均會造成函式呼叫發生異常。

如果被呼叫的合約原始碼並不事前知道,和它們互動會有潛在的風險。當前合約會將自己的控制權交給被呼叫的合約,而對方几乎可以做任何事。即使被呼叫的合約是繼承自一個已知的父合約,但繼承的子合約僅僅被要求正確實現了介面。合約的實現,可以是任意的內容,由此會有風險。另外,準備好處理呼叫你自己系統中的其它合約,可能在第一呼叫結果未返回之前就返回了呼叫的合約。某種程度上意味著,被呼叫的合約可以改變呼叫合約的狀態變數(state variable)來標記當前的狀態。如,寫一個函式,只有當狀態變數(state variables)的值有對應的改變時,才呼叫外部函式,這樣你的合約就不會有可重入性漏洞。

命名引數呼叫和匿名函式引數(Named Calls and Anonymous Function Paramters)

函式呼叫的引數,可以通過指定名字的方式呼叫,但可以以任意的順序,使用方式是{}包含。但引數的型別和數量要與定義一致。

pragma solidity ^0.4.0;

contract C {
    function add(uint val1, uint val2) returns (uint) { return val1 + val2; }

    function g() returns (uint){
        // named arguments
        return add({val2: 2, val1: 1});
    }
}

省略函式名稱(Omitted Function Parameter Names)

沒有使用的引數名可以省略(一般常見於返回值)。這些名字在棧(stack)上存在,但不可訪問。

pragma solidity ^0.4.0;

contract C {
    // omitted name for parameter
    function func(uint k, uint) returns(uint) {
        return k;
    }
}

參考資料