1.作为外部输入参数
有以下两个合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract A {
function set(uint256[] calldata arr) external {}
}
contract B {
function set(uint256[] memory arr) external {}
}
这两个合约中,A传入的数组是calldata存储类型,而B是memory存储类型。我们发布之后,依次执行A、B合约中的set方法,传入的参数为数组[1,2,3,4]
,gas消耗如下:
存储类型 | gas消耗 |
---|---|
calldata | 25710 |
memory | 27281 |
可以发现calldata的gas消耗要比memory要小。因为外部输入的参数到达calldata的步骤要比到达memory的步骤更简单一些,所以消耗gas也要小些。
2.作为函数内调用参数
(1)外部函数为calldata,内部函数为calldata或memory
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract A {
function set(uint256[] calldata arr) external {
_core(arr);
}
function _core(uint256[] calldata arr) private {}
}
contract B {
function set(uint256[] calldata arr) external {
_core(arr);
}
function _core(uint256[] memory arr) private {}
}
这个测试的结果为:
外部函数参数 | 内部函数参数 | gas消耗 |
---|---|---|
calldata | calldata | 25749 |
calldata | memory | 25970 |
这个结果也很好理解。当内部函数参数为memory时,会发生一次从calldata到memory的拷贝
操作,会消耗额外的gas,而从calldata到calldata,就仅仅是引用
,不需要消耗额外的gas。
(2)外部函数为memory,内部函数为calldata或memory
contract C {
function set(uint256[] memory arr) external {
_core(arr);
}
function _core(uint256[] memory arr) private {}
}
contract D {
// TypeError: Invalid type for argument in function call.
// Invalid implicit conversion from uint256[] memory to uint256[] calldata requested.
function set(uint256[] memory arr) external {
_core(arr);
}
function _core(uint256[] calldata arr) private {}
}
D合约代码中,当外部函数参数为memory,内部函数参数为calldata的时候,会报错:从memory
类型的uint256[]隐式转换到calldata
类型的uint256[]是不合理的。
gas消耗的测试结果为:
外部函数参数 | 内部函数参数 | gas消耗 |
---|---|---|
memory | memory | 27314 |
memory | calldata | invalid |
内外部函数参数都为memory类型时,虽然不会发生额外的拷贝操作,但是由于外部输入参数时calldata节省gas的优势,整体的gas消耗量还是最大的。
(3)结果总结
合约 | 外部函数参数 | 内部函数参数 | gas消耗 |
---|---|---|---|
A | calldata | calldata | 25749 |
B | calldata | memory | 25970 |
C | memory | memory | 27314 |
D | memory | calldata | invalid |
网友评论