在我们用solidity的for循环时,大概是这样用的:
for (uint256 i = 0; i < length; ++i) {
...
}
其实在新版本的solidity中,由于uint类型在进行运算时会自动检测溢出,所以在for循环中,有一个改进的写法:
for (uint256 i = 0; i < length; ) {
...
unchecked {
++i
}
}
就是将++i
从for循环表达式中移除,然后在循环体末尾加上unchecked
关键词然后写上++i
。因为for循环中已经有了i < length
这个数值范围检测,所以没有必要每次都做溢出检测。这样会节约很多gas,我们将通过一个例子来说明:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;
contract Test {
uint256[] arr = [1, 2, 3, 4, 5, 6, 7];
uint256[] arrCopy;
constructor() {
arrCopy = new uint256[](arr.length);
}
function getArrCopy() external view returns(uint256[] memory) {
return arrCopy;
}
function unset() external {
arrCopy = new uint256[](arr.length);
}
function origin() external {
uint256 length = arr.length;
arrCopy = new uint256[](length);
for (uint256 i = 0; i < length; ++i) {
arrCopy[i] = arr[i];
}
}
function optimize() external {
uint256 length = arr.length;
arrCopy = new uint256[](length);
for (uint256 i = 0; i < length; ) {
arrCopy[i] = arr[i];
unchecked {
++i;
}
}
}
}
这个合约就是将arr
中的值拷贝到arrCopy
中来。然后origin
方法就是用最普通的for循环来写入,optimize
就是用改进后用unchecked
关键词的for循环来写入。gas消耗如下:
函数 | 写入类型 | gas消耗量 |
---|---|---|
origin | 普通for循环 | 230502 |
optimize | uncheked形式for循环 | 229511 |
节约了比较细微的gas量。
这里的数组长度只有7,所以结果上可能不太明显;如果数组长度够长的话,应该能节约更多的gas。