美文网首页区块链研习社区块链技术与金融白话区块链
【Solidity智能合约系列】03--函数类型

【Solidity智能合约系列】03--函数类型

作者: 唠嗑008 | 来源:发表于2018-05-29 17:21 被阅读5次

    函数类型(Function Types)

    函数也是一种类型,且属于值类型。可以将一个函数赋值给一个函数类型的变量。还可以将一个函数作为参数进行传递。也可以在函数调用中返回一个函数。函数类型有两类:内部(internal)函数和外部(external)函数

    • 内部(internal)函数只能在当前合约内被调用(具体来说,在当前的代码块内,包括内部库函数,和继承的函数中)。

    • 外部(external)函数由地址和函数方法签名两部分组成,可作为外部函数调用的参数,或返回值。

    函数类型的标准规则如下:

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

    如果函数没有返回值,必须省去returns()

    函数类型默认是internal, 因此internal可以省去。与此相反,合约中函数本身默认是public的,可以省略public关键字, 仅仅是当作类型名使用时默认是internal的。

    访问当前合约的函数有2种方式。一种是直接用函数名f, 一种是this.f, 前者用于内部函数,后者用于外部函数。

    pragma solidity ^0.4.0;
    
    contract funcTest{
        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();
        }
    }
    

    如果一个函数类型的变量没有初始化,调用它会产生异常。如果delete一个函数之后再去调用它,也会发生同样的异常。

    如果外部函数类型在Solidity的上下文环境以外的地方使用,他们会被视为function类型。它会编码为20字节的函数所在地址,和在它之前的4字节的函数方法签名一起作为bytes24类型。

    注意:
    合约中public的函数,可以使用internal和external两种方式来调用。internal访问形式为f, external访问形式为this.f

    此外,public(或者external)函数有一个特殊的成员变量selector,它返回一个 ABI function selector:

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

    下面是内部(internal)函数类型使用的例子:

    pragma solidity ^0.4.16;
    
    library ArrayUtils {
      // internal functions can be used in internal library functions because
      // they will be part of the same code context
      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;
      }
    }
    

    下面是外部(external)函数类型使用的例子:

    pragma solidity ^0.4.22;
    
    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));
        emit NewRequest(requests.length - 1);
      }
      function reply(uint requestID, bytes response) public {
        // Here goes the check that the reply comes from a trusted source
        requests[requestID].callback(response);
      }
    }
    
    contract OracleUser {
      Oracle constant oracle = Oracle(0x1234567); // known contract
      function buySomething() {
        oracle.query("USD", this.oracleResponse);
      }
      function oracleResponse(bytes response) public {
        require(
            msg.sender == address(oracle),
            "Only oracle can call this."
        );
        // Use the data
      }
    }
    

    函数可见性分析

    • public - 任意访问
    • private - 仅当前合约内
    • internal - 仅当前合约及所继承的合约
    • external - 仅外部访问(在当前合约内部也只能用外部访问方式访问)

    关于internal和external的理解:

    pragma solidity ^0.4.5;
    
    contract FuntionTest{
        function internalFunc() internal{}
    
        function externalFunc() external{}
    
        function callFunc(){
            //直接使用内部的方式调用
            internalFunc();
    
            //不能在内部调用一个外部函数,会报编译错误。
            //Error: Undeclared identifier.
            //externalFunc();
    
            //不能通过`external`的方式调用一个`internal`
            //Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
            //this.internalFunc();
    
            //使用`this`以`external`的方式调用一个外部函数
            this.externalFunc();
        }
    }
    contract FunctionTest1{
        function externalCall(FuntionTest ft){
            //调用另一个合约的外部函数
            ft.externalFunc();
            
            //不能调用另一个合约的内部函数
            //Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
            //ft.internalFunc();
        }
    }
    

    关于这4种的具体分析,可以参考如下文章
    https://www.jianshu.com/p/c3e3ccb466ec
    https://blog.csdn.net/liyuechun520/article/details/78408608

    参考:
    http://solidity.readthedocs.io/en/develop/types.html#function-types

    相关文章

      网友评论

        本文标题:【Solidity智能合约系列】03--函数类型

        本文链接:https://www.haomeiwen.com/subject/dypujftx.html