循环语句 #

一、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