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
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
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
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
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
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
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
2
3
4
5
6
7
8
9
10
11
12
13
14