函数重载

函数重载

简单理解,一个合约中可以有多个同名的函数,但是这些函数的参数类型需要保证不同

个人理解:

在 Solidity 的底层,调用函数其实并不是通过函数名来调用的,而是通过函数选择器,函数选择器是函数签名的哈希值的前4个字节。函数签名不同,得到的函数选择器就会不同。所以这不会引起冲突。(函数签名:函数名和函数的参数,不使用空格分隔,比如:func(uint256,uint8))

举例,在合约A范围内对函数f进行重载:

contract A {
    function f(uint value) public pure returns (uint out){
        out = value;
    }
    
    function f(uint value, bool really) public pure returns(uint out){
        if (really) 
            out = value;
    }
}

重载函数也存在于外部接口中。如果两个外部可见函数仅区别于 Solidity 内的类型而不是他们的外部类型则会导致错误

// 这段代码编辑器会报错
contract A {
    function f(B value) public pure returns (B out) {
        out = value;
    }

    function f(address value) public pure returns (address out) {
        out = value;
    }
}

contract B {
}

报错原因:虽然上面的函数传入的类型是合约类型,但在 Solidity 的底层,其实他们都是地址,导致函数选择器冲突无法编译

重载解析和参数匹配

通过将当前范围内的函数声明与函数调用中提供的参数相匹配,可以选择重载函数。 如果所有参数都可以隐式地转换为预期类型,则选择函数作为重载候选项。 如果一个候选都没有,解析失败。

返回参数不作为重载解析的依据。

上述情况指的是内部调用,外部调用直接通过函数选择器以和函数匹配,不会出现问题。

重构解析的关键点:

  • 参数匹配:
    • Solidity 会检查你在参数调用中提供的每个函数,看他们是否可以隐式转换为每个重载版本的对应参数类型
    • 如果所有参数都可以隐式转换为某个重载版本的参数类型,那么这个版本就是一个重载候选
  • 选择重载候选:
    • 如果只有一个候选,那么就选择这个。
    • 如果没有候选或有多个候选,解析就会失败,Solidity会报错。
  • 返回参数不影响重载解析
    • 函数的返回类型不参与重载解析。即使两个重载函数的参数类型相同,但返回类型不同,Solidity也不会认为它们是有效的重载。

代码示例:

contract A {
    function f(uint8 val) public pure returns (uint8 out) {
        out = val;
    }

    function f(uint256 val) public pure returns (uint256 out) {
        out = val;
    }
}

首先在合约A中已经存在了重载函数,内部调用函数时:

  • 如果调用方式是f(50),解释器会报错:
    • 因为50可以被隐式转换为uint8,也可以被隐式转换为uint256,两个重载候选冲突
  • 如果调用方式为f(256)则不会出现问题“
    • 因为uint8的最大值为255256不会被隐式转换为uint8,只有一个重载候选。