以太坊Solidity函數的external/internal,public/private區別

image

1

函數類型內部(internal)函數和外部(external)函數

函數類型是一種表示函數的類型。能夠將一個函數賦值給另外一個函數類型的變量,也能夠將一個函數做爲參數進行傳遞,還能在函數調用中返回函數類型變量。 函數類型有兩類:- 內部(internal)函數和 外部(external) 函數:oracle

  • 內部函數只能在當前合約內被調用(更具體來講,在當前代碼塊內,包括內部庫函數和繼承的函數中),由於它們不能在當前合約上下文的外部被執行。 調用一個內部函數是經過跳轉到它的入口標籤來實現的,就像在當前合約的內部調用一個函數。函數

  • 外部函數由一個地址和一個函數簽名組成,能夠經過外部函數調用傳遞或者返回。學習

函數類型表示成以下的形式區塊鏈

function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)]ui

與參數類型相反,返回類型不能爲空 —— 若是函數類型不須要返回,則須要刪除整個 returns (<return types>) 部分。this

函數類型默認是內部函數,所以不須要聲明 internal 關鍵字。 與此相反的是,合約中的函數自己默認是 public 的,只有當它被當作類型名稱時,默認纔是內部函數。編碼

有兩種方法能夠訪問當前合約中的函數:code

  • 一種是直接使用它的名字,f ;繼承

  • 另外一種是使用 this.f 。 事件

前者適用於內部函數,後者適用於外部函數。

若是當函數類型的變量尚未初始化時就調用它的話會引起一個異常。 若是在一個函數被 delete以後調用它也會發生相同的狀況。

若是外部函數類型在 Solidity 的上下文環境之外的地方使用,它們會被視爲 function 類型。 該類型將函數地址緊跟其函數標識一塊兒編碼爲一個 bytes24 類型。

請注意,當前合約的 public 函數既能夠被看成內部函數也能夠被看成外部函數使用。 若是想將一個函數看成內部函數使用,就用 f 調用,若是想將其看成外部函數,使用 this.f 。

除此以外,public(或 external)函數也有一個特殊的成員變量稱做 selector,能夠返回 ABI 函數選擇器:

pragma solidity ^0.4.16;

contract Selector {  function f() public view returns (bytes4) {    return this.f.selector;
 }
}

若是使用內部函數類型的例子:

pragma solidity ^0.4.16;

library ArrayUtils {

  // 內部函數能夠在內部庫函數中使用,

  // 由於它們會成爲同一代碼上下文的一部分

  function map(uint[] memory self, function (uint) pure returns (uint) f)

    internal

    pure

    returns (uint[] memory r)

  {

    r = new uint[](self.length);

    for (uint i = 0; i < self.length; i++) {

      r[i] = f(self[i]); 

   }

  }

  function reduce(

    uint[] memory self,

    function (uint, uint) pure returns (uint) f 

 )

    internal

    pure

    returns (uint r) 

 {

    r = self[0]; 

   for (uint i = 1; i < self.length; i++) {

      r = f(r, self[i]);

    }

  }

  function range(uint length) internal pure returns (uint[] memory r) {

    r = new uint[](length);

    for (uint i = 0; i < r.length; i++) {

      r[i] = i; 

   }

  }

}

contract Pyramid {

  using ArrayUtils for *;

  function pyramid(uint l) public pure returns (uint) {

    return ArrayUtils.range(l).map(square).reduce(sum);

  }

  function square(uint x) internal pure returns (uint) {

    return x * x; 

 }

  function sum(uint x, uint y) internal pure returns (uint) {

    return x + y; 

 }

}

另一個使用外部函數類型的例子:

pragma solidity ^0.4.11;

contract Oracle {

  struct Request {

    bytes data;

    function(bytes memory) external callback;

  }

  Request[] requests;

  event NewRequest(uint);

  function query(bytes data, function(bytes memory) external callback) public {

    requests.push(Request(data, callback));

    NewRequest(requests.length - 1);

  }

  function reply(uint requestID, bytes response) public {

    // 這裏要驗證 reply 來自可信的源

    requests[requestID].callback(response);

  }

}

contract OracleUser { 

 Oracle constant oracle = Oracle(0x1234567); // 已知的合約

  function buySomething() { 

   oracle.query("USD", this.oracleResponse);

  }

  function oracleResponse(bytes response) public {

    require(msg.sender == address(oracle));

    // 使用數據

  }

}

註解 Lambda 表達式或者內聯函數的引入在計劃內,但目前還沒支持。

2

函數可見性說明符public,private,external,internal

public:內部、外部都可見(參考爲存儲/狀態變量建立 getter 函數)

private:僅在當前合約內可見

external:僅在外部可見(僅可修飾函數)——就是說,僅可用於消息調用(即便在合約內調用,也只能經過 this.func 的方式)

internal:僅在內部可見(也就是在當前 Solidity 源代碼文件內都可見,不只限於當前合約內,譯者注)

函數可見性說明符格式:

function myFunction() <visibility specifier> returns (bool) {

    return true;
}

3

函數修改器

pure 修飾函數時:不容許修改或訪問狀態——但目前並非強制的。 view 修飾函數時:不容許修改狀態——但目前不是強制的。 payable 修飾函數時:容許從調用中接收 以太幣Ether 。 constant 修飾狀態變量時:不容許賦值(除初始化之外),不會佔據 存儲插槽storage slot 。 constant 修飾函數時:與 view 等價。 anonymous 修飾事件時:不把事件簽名做爲 topic 存儲。 indexed 修飾事件時:將參數做爲 topic 存儲。

本文做者:HiBlock區塊鏈社區技術佈道者輝哥

原文發佈於簡書

如下是咱們的社區介紹,歡迎各類合做、交流、學習:)

image

相關文章
相關標籤/搜索