solidity的数据结构

1.Mapping的删除

情景:在完成合约的一些交易后要将本次使用过的一些mapping数据删除(或重置),以供下次或其他人使用合约的状态变量

注意:
mapping的delete:只是删除对应某个key的value,而不能直接删除整个mapping,所以要想删除该mapping的每一个key时,往往要把每一个key放进一个动态数组,然后遍历该数组进行删除。

问题:如果要删除一个mapping里的另一个mapping,是直接删除外层mapping,还是要把里层mapping的每个Key都删除?

测试:

// SPDX-License-Identifier: SimPL-2.0
pragma solidity ^0.4.18;
	struct result {
	    int[] results;
	    mapping(int => uint) resultcount;
	}
	mapping(address => result) CSToResult;
	
	//设置值
	function setresults(int _result, uint _count)public {
	    CSToResult[msg.sender].results.push(_result);
	    CSToResult[msg.sender].resultcount[_result] = _count;
	}
	
	//获取results数组和对应某一个result的count
	function getresults(int _result) public view returns(int[],uint){
	    return (CSToResult[msg.sender].results,CSToResult[msg.sender].resultcount[_result]);
	}
	/*
	以下将采取三种方式对CSToResult这个mapping进行删除
	1.直接删除CSToResult[msg.sender];
	2.删除CSToResult[msg.sender]中的每一个result的count及results数组;
	3.在2的基础上再删除删除CSToResult[msg.sender];
	*/
	function deleteData1()public {
	
	    delete CSToResult[msg.sender];
	}
	
	function deleteData2()public {
	    
	    for(uint i =0; i <CSToResult[msg.sender].results.length;i++){
	        delete CSToResult[msg.sender].resultcount[CSToResult[msg.sender].results[i]];
	    }
	    delete CSToResult[msg.sender].results;
	}
	
	function deleteData3()public {
	    for(uint i =0; i <CSToResult[msg.sender].results.length;i++){
	        delete CSToResult[msg.sender].resultcount[CSToResult[msg.sender].results[i]];
	    }
	    delete CSToResult[msg.sender].results;
	    delete CSToResult[msg.sender];
	}

注意:

这里不能把CSToResult设置成public的

deletemapping 参数设置_智能合约


我觉得是因为结构体里边含了个动态数组的缘故(之前用过结构体里含一个mapping,也可以设置成public类型,所以应该不是内层mapping的问题)

下面对每一种方法进行测试;
我们分别把1,1;
2,2;
3,3;
3,5 push进去,然后分别用三个函数进行删除,观察删除效果及gas消耗情况

注意:gas cost可以分为Execution cost和transaction cost

Execution cost包括存储全局变量以及方法调用相关的运行环境的开销。同一个函数,每次调用时的execution cost有可能是不同的。(比如全局变量发生了变化导致)

而Transaction cost和编译后的合约代码长度相关,也和execution cost相关。同一个合约,每次执行时transaction cost - execution cost的值应该是不变的。

删除前先查看一下

deletemapping 参数设置_区块链_02

1.直接删除CSToResult[msg.sender]:调用deleteData1()

gas消耗:

deletemapping 参数设置_deletemapping 参数设置_03

再查看一下

deletemapping 参数设置_动态数组_04


发现,仅仅将大Mapping对应struct里的其他数据结构变为了初值,里层的mapping其实是不受影响的。2.调用deleteData2()

gas消耗:

deletemapping 参数设置_动态数组_05

再查看一下

deletemapping 参数设置_deletemapping 参数设置_06


这次基本上成功了,但是不知道外层mapping有没有成功删除。

3.调用deleteData3()
gas消耗:

deletemapping 参数设置_动态数组_07

再查看一下

deletemapping 参数设置_deletemapping 参数设置_06


和2的效果是一样的,但是gas明显多了,所以删除外层mapping应该是有用的。

…写到这里我又想到了第四种方法,就是不删除结构体里的动态数组,反正结果是一样的。。稍微测试了一下

function deleteData4()public {
	    
	    for(uint i =0; i <CSToResult[msg.sender].results.length;i++){
	        delete CSToResult[msg.sender].resultcount[CSToResult[msg.sender].results[i]];
	    }
	   // delete CSToResult[msg.sender].results;
	    delete CSToResult[msg.sender];
	}

deletemapping 参数设置_动态数组_09

效果一样,gas比方法3稍微少一点,也只比2多了百十wei,…还不错

总结:要想保险一点,要把内层mapping删除,再把外层mapping删除,这样应该是技能达到效果又能省亿点点gas的吧