以数组长度为条件遍历数组
Looping over array with array length as condition
假设我们有一个包含 uint256 动态状态数组 fooArray
的合同。在同一个合约中,有一个具有以下循环的函数:
for (uint256 i = 0; i < fooArray.length; ++i) {
// Some code here, that does not modify array in any way.
}
检查循环条件是否需要在每次迭代时从存储中读取 fooArray
的长度,或者它不被视为从存储中读取值?
我是否应该预先将数组的长度保存到局部变量并将该变量用作循环条件以节省gas?
我创建了新合约,然后在没有临时变量的情况下执行了 3 次,然后再次创建了新合约并使用临时变量执行。 Remix Javscript VM 和 Rinkeby 网络的结果完全相同,具有临时变量的函数需要更少的 gas。可以读取字节码和 Gas Costs from Yellow Paper 但是我认为很明显使用临时变量更好。
实体代码:
pragma solidity ^0.8.0;
contract EstimateGas {
uint[] public fooArray;
constructor (){
for (uint256 i = 0; i < 500; ++i) {
fooArray.push(i);
}
}
function changeNoTemp() public{
for (uint256 i = 0; i < fooArray.length; ++i) {
fooArray[i] = fooArray[i] +1;
}
}
function changeWithTemp() public{
uint arrayLen = fooArray.length;
for (uint256 i = 0; i < arrayLen; ++i) {
fooArray[i] = fooArray[i] +1;
}
}
}
gas 执行成本
changeNoTemp()
1) 2965426 gas
2) 2948326 gas
3) 2948326 gas
changeWithTemp()
1) 2911461 gas
2) 2894361 gas
3) 2894361 gas
假设我们有一个包含 uint256 动态状态数组 fooArray
的合同。在同一个合约中,有一个具有以下循环的函数:
for (uint256 i = 0; i < fooArray.length; ++i) {
// Some code here, that does not modify array in any way.
}
检查循环条件是否需要在每次迭代时从存储中读取 fooArray
的长度,或者它不被视为从存储中读取值?
我是否应该预先将数组的长度保存到局部变量并将该变量用作循环条件以节省gas?
我创建了新合约,然后在没有临时变量的情况下执行了 3 次,然后再次创建了新合约并使用临时变量执行。 Remix Javscript VM 和 Rinkeby 网络的结果完全相同,具有临时变量的函数需要更少的 gas。可以读取字节码和 Gas Costs from Yellow Paper 但是我认为很明显使用临时变量更好。
实体代码:
pragma solidity ^0.8.0;
contract EstimateGas {
uint[] public fooArray;
constructor (){
for (uint256 i = 0; i < 500; ++i) {
fooArray.push(i);
}
}
function changeNoTemp() public{
for (uint256 i = 0; i < fooArray.length; ++i) {
fooArray[i] = fooArray[i] +1;
}
}
function changeWithTemp() public{
uint arrayLen = fooArray.length;
for (uint256 i = 0; i < arrayLen; ++i) {
fooArray[i] = fooArray[i] +1;
}
}
}
gas 执行成本
changeNoTemp()
1) 2965426 gas
2) 2948326 gas
3) 2948326 gas
changeWithTemp()
1) 2911461 gas
2) 2894361 gas
3) 2894361 gas