You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solidity/Remix:字符串去重函数执行数组成员赋值操作为何失败

问题根源

你遇到的回滚、调试器卡住的核心原因是Solidity内存(memory)动态数组使用规则错误:

  • 所有memory类型的动态数组在使用前必须显式指定初始长度,你声明的string[] memory deduped;没有指定长度,默认长度为0,此时直接访问deduped[0]属于数组越界访问,直接触发链上回滚。
  • 其次原代码后续逻辑也存在问题:memory数组的长度是固定的,初始化后无法像storage数组一样通过push或者直接修改.length扩容,你后续写的deduped[deduped.length]=key也会持续触发越界错误。
  • 另外去重内层循环的遍历上限写的是keys.length,应该是当前已经去重后的数组长度,否则会访问到deduped的空索引位置。

修复方案

首先需要先确定去重后数组的最大可能长度(就是原数组长度),先初始化对应长度的memory数组,记录实际去重后的元素个数,最后再截取出实际有效长度的数组返回即可。
修复后的完整代码如下:

pragma solidity >=0.7.0 <0.9.0;
contract Tester  {
    
    function dedupeKeys(string[] memory keys) public pure returns(string[] memory) {
        if (keys.length == 0) return new string[](0);  
        // 先初始化最大可能长度的memory数组
        string[] memory tempDeduped = new string[](keys.length);
        // 记录实际去重后的元素个数
        uint dedupedCount = 0;
        bool found;
        string memory key;

        for(uint i=0; i<keys.length; i++) {
            found = false;
            key = keys[i];
            // 只遍历已经存入去重数组的有效元素
            for(uint j=0; j<dedupedCount; j++) {
                if(equal(tempDeduped[j], key)) {
                    found = true;
                    break; // 匹配到重复就提前退出,节省gas
                }
            }
            if (!found) {
                tempDeduped[dedupedCount] = key;
                dedupedCount++;
            }
        }

        // 截取实际有效长度的数组返回
        string[] memory deduped = new string[](dedupedCount);
        for(uint i=0; i<dedupedCount; i++) {
            deduped[i] = tempDeduped[i];
        }
        return deduped;
    }
    
    function equal(string memory _base, string memory _value)
        internal
        pure
        returns (bool) {
        bytes memory _baseBytes = bytes(_base);
        bytes memory _valueBytes = bytes(_value);

        if (_baseBytes.length != _valueBytes.length) {
            return false;
        }

        for (uint i = 0; i < _baseBytes.length; i++) {
            if (_baseBytes[i] != _valueBytes[i]) {
                return false;
            }
        }

        return true;
    }

}

额外优化点

  • 内层循环匹配到重复元素后添加了break语句,不需要继续遍历剩余元素,减少不必要的gas消耗
  • 避免了重复的越界访问风险,逻辑和原需求完全一致
  • 空输入的边界处理更健壮

内容的提问来源于stack exchange,提问作者GGizmos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 15:57:03