Solidity 合约方法与调用

2022-12-29 Web3 Solidity

# 一、合约方法的可见性

  • external:只有其他合约和账户可调用。
  • public:任何合约都可调用。
  • internal:只有在继承合约可调用。
  • private:只有定义了该方法的合约内部可调用。

# 1.1 external

外部函数是合约接口的一部分,可以从其他合约通过交易发起调用。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Function {
    
    function externalFunc() external {}

    function callFunc() public {
        // 编译报错,不能从内部直接调用
        // externalFunc();

        // 以外部方式调用,this 可以看做当前合约的地址
        this.externalFunc();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 1.2 public

公开函数同样是合约接口的一部分,可以从其他合约通过交易发起调用,也可以从内部直接调用。

public 是访问权限最大的修饰符。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Function {
    
    function publicFunc() public {}

    function callFunc() public {
        // 从内部直接调用
        publicFunc();

        // 以外部方式调用
        this.publicFunc();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 1.3 internal

内部函数只能通过内部访问(例如在当前合约中)调用,或在继承的合约里调用。不能使用外部访问的方式进行调用。

注意:调用时不能加前缀 this

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Function {
    
    function internalFunc() internal {}

    function callFunc() public {
        // 从内部直接调用
        internalFunc();

        // 编译报错,不能以外部方式调用
        // this.internalFunc();
    }
}

contract FunctionChild is Function
{
    // 子合约中调用
    function callFuncChild() public {
        internalFunc();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 1.4 private

私有函数仅在当前合约中可以访问,在继承的合约中不可访问。

private 是访问权限最小的修饰符。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Function {
    
    function internalFunc() private {}

    function callFunc() public {
        // 从内部直接调用
        internalFunc();

        // 编译报错,不能以外部方式调用
        // this.internalFunc();
    }
}

contract FunctionChild is Function
{
    // 编译报错,子合约中不能调用
    function callFuncChild() public {
        // internalFunc();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 二、合约方法定义

function 函数名(参数) public|private|internal|external [pure|view|constant|payable] [returns (返回类型)]
1
  • pure:不可读取且不可更改合约中的状态变量。
  • view:可读取但不可更改合约中的状态变量。
  • constant:常量,不可更改(与 view 作用相同)。
  • payable:表示调用这个函数时,可以附加发送一些 ETH;如果没有该修饰符,附加 ETH 会出错。

# 三、合约方法调用

# 3.1 内部函数调用

在当前同一个合约中,函数可以直接进行内部调用,也可以进行递归调用。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract C {
    function g(uint a) public pure returns (uint ret) {
        return f();
    }
    function f() internal pure returns (uint ret) {
        return g(7) + f();
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 3.2 外部函数调用

如果想要调用其他合约的函数,需要外部调用。对于一个外部调用,所有的函数参数都需要被复制到内存。

当调用其他合约的函数时,需要在函数调用是指定发送的 Wei 和 gas 数量,可以使用特定选项 {value: 10, gas: 10000}

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract InfoFeed {
    // 必须用 payable 修饰,否则 value 参数将不可用
    function info() public payable returns (uint ret) {
        return 42;
    }
}

contract Consumer {
    InfoFeed feed;
    
    function setFeed(InfoFeed addr) public {
        feed = addr;
    }
    function callFeed() public {
        feed.info{value: 10, gas: 800}();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3.3 命名参数调用

参数列表必须按名称与函数声明中的参数列表相符,但可以按任意顺序排列。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract C {
    mapping(uint => uint) data;

    function f() public {
        set({value: 2, key: 3});
    }

    function set(uint key, uint value) public {
        data[key] = value;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 四、参考资料

Last Updated: 2023-01-28 4:31:25