Solidity語言學習筆記————21、函式的訪問許可權和可見性

FLy_鵬程萬里發表於2018-06-21

在之前的文章中我們介紹了Solidity語言函式的一些基本語法。下面來繼續介紹作為一個分散式網路語言所特有的internal和external這兩種不同的函式呼叫方式,以及Solidity提供的對函式呼叫時的可見性控制語法。

呼叫方式

Solidity封裝了兩種函式的呼叫方式internal和external。

internal

internal呼叫,實現時轉為簡單的EVM跳轉,所以它能直接使用上下文環境中的資料,對於引用傳遞時將會變得非常高效(不用拷貝資料)。

在當前的程式碼單元內,如對合約內函式,引入的庫函式,以及父類合約中的函式直接使用即是以internal方式的呼叫。我們來看個簡單的例子:

pragma solidity ^0.4.0;

contract Test {
    function f(){}
    
    //以`internal`的方式呼叫
    function callInternally(){
        f();
    }
}

在上述程式碼中,callInternally()internal的方式對f()函式進行了呼叫。

external

external呼叫,實現為合約的外部訊息呼叫。所以在合約初始化時不能external的方式呼叫自身函式,因為合約還未初始化完成。下面來看一個以external方式呼叫的例子:

pragma solidity ^0.4.0;

contract A{
    function f(){}
}

contract B{
    //以`external`的方式呼叫另一合約中的函式
    function callExternal(A a){
        a.f();
    }
}

雖然當前合約AB的程式碼放在一起,但部署到網路上後,它們是兩個完全獨立的合約,它們之間的方法呼叫是通過訊息呼叫。上述程式碼中,在合約B中的callExternal()external的方式呼叫了合約Af()

external呼叫時,實際是向目標合約傳送一個訊息呼叫。訊息中的函式定義部分是一個24位元組大小的訊息體,20位元組為地址,4位元組為函式簽名。

this

我們可以在合約的呼叫函式前加this.來強制以external方式的呼叫。需要注意的是這裡的this的用法與大多數語言的都不一致。

pragma solidity ^0.4.0;

contract A{
    function f() internal{}
    
    function callInternally(){
        f();
    }
    
    //以`external`的方式呼叫
    //f()只能以`internal`的方式呼叫
    //Untitled3:7:9: Error: Member "f" not found or not visible after argument-dependent lookup in contract A
    function callExternally(){
        //this.f();
    }
}

呼叫方式說明

上面所提到的internalexternal指的函式呼叫方式,請不要與後面的函式可見性宣告的externalpublicinternalprivate弄混。宣告只是意味著這個函式需要使用相對應的呼叫方式去呼叫。後續說明中會用以某某方式呼叫,來強調

二、函式的可見性

Solidity為函式提供了四種可見性,externalpublicinternalprivate

external

  • 宣告為external的可以從其它合約或通過Transaction進行呼叫,所以宣告為external的函式是合約對外介面的一部分。
  • 不能以internal的方式進行呼叫。
  • 有時在接收大的資料陣列時效能更好。
pragma solidity ^0.4.5;

contract FuntionTest{
    function externalFunc() external{}

    function callFunc(){
        //以`internal`的方式呼叫函式報錯
        //Error: Undeclared identifier.
        //externalFunc();
        
        //以`external`的方式呼叫函式
        this.externalFunc();
    }
}

宣告為externalexternalFunc()只能以external的方式進行呼叫,以internal的方式呼叫會報Error: Undeclared identifier.

public

  • 函式預設宣告為public
  • public的函式既允許以internal的方式呼叫,也允許以external的方式呼叫。
  • public的函式由於被外部合約訪問,是合約對外介面的一部分。
pragma solidity ^0.4.5;

contract FuntionTest{
    //預設是public函式
    function publicFunc(){}

    function callFunc(){
        //以`internal`的方式呼叫函式
        publicFunc();
        
        //以`external`的方式呼叫函式
        this.publicFunc();
    }
}

我們可以看到宣告為publicpublicFunc()允許兩種呼叫方式。

internal

  • 在當前的合約或繼承的合約中,只允許以internal的方式呼叫。
pragma solidity ^0.4.5;

contract A{
    //預設是public函式
    function internalFunc() internal{}

    function callFunc(){
        //以`internal`的方式呼叫函式
        internalFunc();
    }
}
contract B is A{
    //子合約中呼叫
    function callFunc(){
        internalFunc();
    }
}

上述例子中宣告為internalinternalFunc()在定義合約,和子合約中均只能以internal的方式可以進行呼叫。

private

  • 只能在當前合約中被訪問(不可在被繼承的合約中訪問)。
  • 即使宣告為private,仍能被所有人檢視到裡面的資料。訪問許可權只是阻止了其它合約訪問函式或修改資料。

pragma solidity ^0.4.5;

contract A{
    //預設是public函式
    function privateFunc() private{}

    function callFunc(){
        //以`internal`的方式呼叫函式
        privateFunc();
    }
}
contract B is A{
    //不可呼叫`private`
    function callFunc(){
        //privateFunc();
    }
}

上述例子中,宣告為privateprivateFunc()只能在定義的合約中以internal的方式進行呼叫。


相關文章