1、背景
在以太坊NFT中,需要使用Set进行NFT(本质是存的NFT的唯一ID)的存储,以太坊本身没有Set的概念,只有数组。基于单数组实现Set,每次删除value,都需要遍历数组然后逐个调整,由于太坊执行操作需要消耗gas,这种调整比较消耗gas,因此会基于双数组来实现删除功能。
2、原理图
3、solidity代码实现
mapping(address => uint256[]) internal ownerTokens;
mapping(uint256 => uint256) internal tokenIndexs;
mapping(uint256 => address) internal tokenOwners;
function addTokenTo(address to, uint256 tokenId) internal {
uint256[] storage tokens = ownerTokens[to];
tokenIndexs[tokenId] = tokens.length;
tokens.push(tokenId);
tokenOwners[tokenId] = to;
}
function removeTokenFrom(address from, uint256 tokenId) internal {
uint256 index = tokenIndexs[tokenId];
uint256[] storage tokens = ownerTokens[from];
uint256 indexLast = tokens.length - 1;
uint256 tokenIdLast = tokens[indexLast];
tokens[index] = tokenIdLast;
tokenIndexs[tokenIdLast] = index;
tokens.pop();
delete tokenOwners[tokenId];
}
添加操作
1、tokenIndexs是一个数组,它的下标是要保存的tokenId,它的值是当前tokenId的数量,比如第一次存入tokenId=7的NFT,当前没有NFT,那么tokenIndexs[7] = 0,第二次存入tokenId=5的NFT,当前有一个NFT,那么tokenIndexs[5] = 1,第三次存入tokenId=9的NFT,当前有两个NFT,那么tokenIndexs[9] = 2
2、tokens是一个数组,它保存了所有的tokenId,上面三次操作后tokens=[7,5,9]
删除操作,删除tokenId=7
1、将最近加入的元素设置到要删除元素的位置,也就是tokenIndexs[9] = tokenIndexs[7] ,由于tokenIndexs[7] =0,这时候tokenIndexs[9]就是0,然后让tokens[0]=9
2、然后调用pop删除tokens最后一个元素