循环语句 #
一、for循环 #
1.1 基本语法 #
solidity
for (初始化; 条件; 迭代) {
// 循环体
}
1.2 使用示例 #
solidity
contract ForLoop {
// 基本for循环
function sum(uint256 n) public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 1; i <= n; i++) {
total += i;
}
return total;
}
// 遍历数组
function sumArray(uint256[] memory arr) public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
// 查找元素
function findIndex(uint256[] memory arr, uint256 value)
public
pure
returns (int256)
{
for (uint256 i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return int256(i);
}
}
return -1;
}
}
1.3 for循环变体 #
solidity
contract ForLoopVariants {
// 省略初始化
function noInit() public pure returns (uint256) {
uint256 i = 0;
uint256 total = 0;
for (; i < 10; i++) {
total += i;
}
return total;
}
// 省略条件(需要手动break)
function noCondition() public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; ; i++) {
if (i >= 10) break;
total += i;
}
return total;
}
// 省略迭代
function noIteration() public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < 10; ) {
total += i;
i++;
}
return total;
}
}
二、while循环 #
2.1 基本语法 #
solidity
while (条件) {
// 循环体
}
2.2 使用示例 #
solidity
contract WhileLoop {
// 基本while循环
function countdown(uint256 n) public pure returns (uint256) {
uint256 count = 0;
while (n > 0) {
count++;
n--;
}
return count;
}
// 查找第一个满足条件的元素
function findFirstGreaterThan(
uint256[] memory arr,
uint256 threshold
) public pure returns (int256) {
uint256 i = 0;
while (i < arr.length) {
if (arr[i] > threshold) {
return int256(i);
}
i++;
}
return -1;
}
// 计算位数
function countDigits(uint256 n) public pure returns (uint256) {
uint256 count = 0;
while (n > 0) {
count++;
n /= 10;
}
return count == 0 ? 1 : count;
}
}
三、do-while循环 #
3.1 基本语法 #
solidity
do {
// 循环体
} while (条件);
3.2 使用示例 #
solidity
contract DoWhileLoop {
// 基本do-while循环
function executeAtLeastOnce(uint256 n) public pure returns (uint256) {
uint256 count = 0;
do {
count++;
n--;
} while (n > 0);
return count;
}
// 确保至少执行一次
function processUntilCondition(uint256 value) public pure returns (uint256) {
uint256 result = 0;
do {
result += value;
value /= 2;
} while (value > 0);
return result;
}
}
四、循环控制语句 #
4.1 break #
solidity
contract BreakStatement {
// 提前退出循环
function findFirst(uint256[] memory arr, uint256 target)
public
pure
returns (int256)
{
for (uint256 i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return int256(i); // 找到后立即返回
}
}
return -1;
}
// 使用break退出循环
function findFirstWithBreak(uint256[] memory arr, uint256 target)
public
pure
returns (int256)
{
int256 index = -1;
for (uint256 i = 0; i < arr.length; i++) {
if (arr[i] == target) {
index = int256(i);
break; // 退出循环
}
}
return index;
}
}
4.2 continue #
solidity
contract ContinueStatement {
// 跳过当前迭代
function sumEvenNumbers(uint256[] memory arr) public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0) {
continue; // 跳过奇数
}
total += arr[i];
}
return total;
}
// 过滤处理
function processPositiveOnly(int256[] memory arr)
public
pure
returns (int256[] memory)
{
uint256 count = 0;
for (uint256 i = 0; i < arr.length; i++) {
if (arr[i] <= 0) continue;
count++;
}
int256[] memory result = new int256[](count);
uint256 index = 0;
for (uint256 i = 0; i < arr.length; i++) {
if (arr[i] <= 0) continue;
result[index++] = arr[i];
}
return result;
}
}
五、循环与Gas限制 #
5.1 Gas限制问题 #
solidity
contract GasLimit {
// 危险:可能超出区块Gas限制
function dangerousLoop(uint256[] memory arr) public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
// 安全:限制循环次数
uint256 public constant MAX_ITERATIONS = 1000;
function safeLoop(uint256[] memory arr) public pure returns (uint256) {
require(arr.length <= MAX_ITERATIONS, "Array too large");
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
}
5.2 分批处理 #
solidity
contract BatchProcessing {
uint256[] public data;
uint256 public processedIndex;
event BatchProcessed(uint256 from, uint256 to);
// 分批处理大量数据
function processBatch(uint256 batchSize) public returns (uint256) {
uint256 endIndex = processedIndex + batchSize;
if (endIndex > data.length) {
endIndex = data.length;
}
uint256 total = 0;
for (uint256 i = processedIndex; i < endIndex; i++) {
total += data[i];
}
emit BatchProcessed(processedIndex, endIndex);
processedIndex = endIndex;
return total;
}
function addData(uint256[] memory newData) public {
for (uint256 i = 0; i < newData.length; i++) {
data.push(newData[i]);
}
}
function resetProcessing() public {
processedIndex = 0;
}
}
六、实际应用示例 #
6.1 批量转账 #
solidity
contract BatchTransfer {
address public owner;
uint256 public constant MAX_BATCH_SIZE = 100;
event TransferExecuted(address indexed recipient, uint256 amount);
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
// 批量转账
function batchTransfer(
address[] memory recipients,
uint256[] memory amounts
) public payable onlyOwner {
require(recipients.length == amounts.length, "Length mismatch");
require(recipients.length <= MAX_BATCH_SIZE, "Batch too large");
uint256 totalAmount = 0;
for (uint256 i = 0; i < amounts.length; i++) {
totalAmount += amounts[i];
}
require(msg.value >= totalAmount, "Insufficient ETH");
for (uint256 i = 0; i < recipients.length; i++) {
require(recipients[i] != address(0), "Invalid recipient");
payable(recipients[i]).transfer(amounts[i]);
emit TransferExecuted(recipients[i], amounts[i]);
}
// 退还多余的ETH
if (msg.value > totalAmount) {
payable(msg.sender).transfer(msg.value - totalAmount);
}
}
}
6.2 多重签名钱包 #
solidity
contract MultiSigWallet {
uint256 public required;
address[] public owners;
mapping(address => bool) public isOwner;
mapping(uint256 => mapping(address => bool)) public confirmations;
struct Transaction {
address destination;
uint256 value;
bytes data;
bool executed;
}
Transaction[] public transactions;
event TransactionSubmitted(uint256 indexed txId, address indexed sender);
event TransactionConfirmed(uint256 indexed txId, address indexed owner);
event TransactionExecuted(uint256 indexed txId);
struct Transaction {
address destination;
uint256 value;
bytes data;
bool executed;
}
Transaction[] public transactions;
event Submission(uint256 indexed transactionId);
event Confirmation(address indexed owner, uint256 indexed transactionId);
event Execution(uint256 indexed transactionId);
constructor(address[] memory _owners, uint256 _required) {
require(_owners.length >= _required, "Invalid requirement");
require(_required > 0, "Required must be positive");
for (uint256 i = 0; i < _owners.length; i++) {
require(_owners[i] != address(0), "Invalid owner");
require(!isOwner[_owners[i]], "Duplicate owner");
isOwner[_owners[i]] = true;
owners.push(_owners[i]);
}
required = _required;
}
function submitTransaction(
address destination,
uint256 value,
bytes memory data
) public returns (uint256) {
require(isOwner[msg.sender], "Not owner");
transactions.push(Transaction({
destination: destination,
value: value,
data: data,
executed: false
}));
uint256 transactionId = transactions.length - 1;
emit Submission(transactionId);
confirmTransaction(transactionId);
return transactionId;
}
function confirmTransaction(uint256 transactionId) public {
require(isOwner[msg.sender], "Not owner");
require(!confirmations[transactionId][msg.sender], "Already confirmed");
require(!transactions[transactionId].executed, "Already executed");
confirmations[transactionId][msg.sender] = true;
emit Confirmation(msg.sender, transactionId);
if (isConfirmed(transactionId)) {
executeTransaction(transactionId);
}
}
function isConfirmed(uint256 transactionId) public view returns (bool) {
uint256 count = 0;
for (uint256 i = 0; i < owners.length; i++) {
if (confirmations[transactionId][owners[i]]) {
count++;
}
if (count == required) {
return true;
}
}
return false;
}
function executeTransaction(uint256 transactionId) public {
require(isConfirmed(transactionId), "Not confirmed");
Transaction storage txn = transactions[transactionId];
require(!txn.executed, "Already executed");
txn.executed = true;
(bool success, ) = txn.destination.call{value: txn.value}(txn.data);
require(success, "Execution failed");
emit Execution(transactionId);
}
}
6.3 投票系统 #
solidity
contract Voting {
struct Proposal {
string description;
uint256 voteCount;
bool executed;
}
mapping(address => bool) public voters;
mapping(uint256 => mapping(address => bool)) public hasVoted;
Proposal[] public proposals;
address public admin;
event ProposalCreated(uint256 indexed id, string description);
event Voted(address indexed voter, uint256 indexed proposalId);
event ProposalExecuted(uint256 indexed id);
constructor() {
admin = msg.sender;
}
modifier onlyAdmin() {
require(msg.sender == admin, "Not admin");
_;
}
function addVoter(address voter) public onlyAdmin {
voters[voter] = true;
}
function createProposal(string memory description) public onlyAdmin {
proposals.push(Proposal({
description: description,
voteCount: 0,
executed: false
}));
emit ProposalCreated(proposals.length - 1, description);
}
function vote(uint256 proposalId) public {
require(voters[msg.sender], "Not a voter");
require(!hasVoted[proposalId][msg.sender], "Already voted");
require(!proposals[proposalId].executed, "Proposal executed");
hasVoted[proposalId][msg.sender] = true;
proposals[proposalId].voteCount++;
emit Voted(msg.sender, proposalId);
}
function executeProposal(uint256 proposalId) public onlyAdmin {
Proposal storage proposal = proposals[proposalId];
require(!proposal.executed, "Already executed");
uint256 totalVoters = 0;
// 注意:这里需要维护一个voter数组来遍历
// 或者使用其他方式统计
proposal.executed = true;
emit ProposalExecuted(proposalId);
}
function getResults() public view returns (uint256[] memory) {
uint256[] memory results = new uint256[](proposals.length);
for (uint256 i = 0; i < proposals.length; i++) {
results[i] = proposals[i].voteCount;
}
return results;
}
}
七、最佳实践 #
7.1 限制循环次数 #
solidity
contract LimitLoop {
uint256 public constant MAX_LOOP = 100;
function safeLoop(uint256[] memory arr) public pure returns (uint256) {
require(arr.length <= MAX_LOOP, "Array too large");
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
}
7.2 使用缓存优化 #
solidity
contract CacheOptimization {
// 不推荐:每次都读取storage
function sumBad(uint256[] storage arr) internal view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
total += arr[i]; // 每次都从storage读取
}
return total;
}
// 推荐:缓存数组长度
function sumGood(uint256[] storage arr) internal view returns (uint256) {
uint256 total = 0;
uint256 len = arr.length; // 缓存长度
for (uint256 i = 0; i < len; i++) {
total += arr[i];
}
return total;
}
}
7.3 避免不必要的循环 #
solidity
contract AvoidUnnecessaryLoop {
mapping(address => uint256) public balances;
// 不推荐:遍历查找
function hasBalanceBad(address[] memory users)
public
view
returns (bool)
{
for (uint256 i = 0; i < users.length; i++) {
if (balances[users[i]] > 0) {
return true;
}
}
return false;
}
// 推荐:直接查询
function hasBalanceGood(address user) public view returns (bool) {
return balances[user] > 0;
}
}
八、总结 #
循环语句要点:
| 循环类型 | 说明 | 使用场景 |
|---|---|---|
| for | 计数循环 | 已知次数的迭代 |
| while | 条件循环 | 不确定次数的迭代 |
| do-while | 至少执行一次 | 需要先执行后判断 |
使用建议:
- 限制循环次数,避免Gas超限
- 使用缓存优化性能
- 考虑分批处理大量数据
- 避免不必要的循环
接下来,让我们学习异常处理!
最后更新:2026-03-27