当前位置: 首页 > news >正文

Michael.W基于Foundry精读Openzeppelin第20期——EnumerableMap.sol

0. 版本

[openzeppelin]:v4.8.3,[forge-std]:v1.5.6

0.1 EnumerableMap.sol

Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/structs/EnumerableMap.sol

EnumerableMap库提供了Bytes32ToBytes32Map、UintToUintMap、UintToAddressMap、AddressToUintMap和Bytes32ToUintMap五种可迭代元素的map,分别适用于(bytes32, bytes32)、(uint256, uint256)、(uint256, address)、(address, uint256)和(bytes32, uint256)类型的键值对。每种map都提供了增添/更新/删除键值对及由键查值等操作。所有操作的时间复杂度均为O(1)。

1. 目标合约

封装EnumerableMap library成为一个可调用合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/structs/MockEnumerableMap.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;import "openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol";contract MockBytes32ToBytes32Map {using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map;EnumerableMap.Bytes32ToBytes32Map _bytes32ToBytes32Map;function set(bytes32 key, bytes32 value) external returns (bool) {return _bytes32ToBytes32Map.set(key, value);}function remove(bytes32 key) external returns (bool) {return _bytes32ToBytes32Map.remove(key);}function contains(bytes32 key) external view returns (bool) {return _bytes32ToBytes32Map.contains(key);}function length() external view returns (uint) {return _bytes32ToBytes32Map.length();}function at(uint index) external view returns (bytes32, bytes32) {return _bytes32ToBytes32Map.at(index);}function tryGet(bytes32 key) external view returns (bool, bytes32){return _bytes32ToBytes32Map.tryGet(key);}function get(bytes32 key) external view returns (bytes32) {return _bytes32ToBytes32Map.get(key);}function get(bytes32 key, string memory errorMessage) external view returns (bytes32) {return _bytes32ToBytes32Map.get(key, errorMessage);}
}contract MockUintToUintMap {using EnumerableMap for EnumerableMap.UintToUintMap;EnumerableMap.UintToUintMap _uintToUintMap;function set(uint key, uint value) external returns (bool) {return _uintToUintMap.set(key, value);}function remove(uint key) external returns (bool) {return _uintToUintMap.remove(key);}function contains(uint key) external view returns (bool) {return _uintToUintMap.contains(key);}function length() external view returns (uint) {return _uintToUintMap.length();}function at(uint index) external view returns (uint, uint) {return _uintToUintMap.at(index);}function tryGet(uint key) external view returns (bool, uint){return _uintToUintMap.tryGet(key);}function get(uint key) external view returns (uint) {return _uintToUintMap.get(key);}function get(uint key, string memory errorMessage) external view returns (uint) {return _uintToUintMap.get(key, errorMessage);}
}contract MockUintToAddressMap {using EnumerableMap for EnumerableMap.UintToAddressMap;EnumerableMap.UintToAddressMap _uintToAddressMap;function set(uint key, address value) external returns (bool) {return _uintToAddressMap.set(key, value);}function remove(uint key) external returns (bool) {return _uintToAddressMap.remove(key);}function contains(uint key) external view returns (bool) {return _uintToAddressMap.contains(key);}function length() external view returns (uint) {return _uintToAddressMap.length();}function at(uint index) external view returns (uint, address) {return _uintToAddressMap.at(index);}function tryGet(uint key) external view returns (bool, address){return _uintToAddressMap.tryGet(key);}function get(uint key) external view returns (address) {return _uintToAddressMap.get(key);}function get(uint key, string memory errorMessage) external view returns (address) {return _uintToAddressMap.get(key, errorMessage);}
}contract MockAddressToUintMap {using EnumerableMap for EnumerableMap.AddressToUintMap;EnumerableMap.AddressToUintMap _addressToUintMap;function set(address key, uint value) external returns (bool) {return _addressToUintMap.set(key, value);}function remove(address key) external returns (bool) {return _addressToUintMap.remove(key);}function contains(address key) external view returns (bool) {return _addressToUintMap.contains(key);}function length() external view returns (uint) {return _addressToUintMap.length();}function at(uint index) external view returns (address, uint) {return _addressToUintMap.at(index);}function tryGet(address key) external view returns (bool, uint){return _addressToUintMap.tryGet(key);}function get(address key) external view returns (uint) {return _addressToUintMap.get(key);}function get(address key, string memory errorMessage) external view returns (uint) {return _addressToUintMap.get(key, errorMessage);}
}contract MockBytes32ToUintMap {using EnumerableMap for EnumerableMap.Bytes32ToUintMap;EnumerableMap.Bytes32ToUintMap _bytes32ToUintMap;function set(bytes32 key, uint value) external returns (bool) {return _bytes32ToUintMap.set(key, value);}function remove(bytes32 key) external returns (bool) {return _bytes32ToUintMap.remove(key);}function contains(bytes32 key) external view returns (bool) {return _bytes32ToUintMap.contains(key);}function length() external view returns (uint) {return _bytes32ToUintMap.length();}function at(uint index) external view returns (bytes32, uint) {return _bytes32ToUintMap.at(index);}function tryGet(bytes32 key) external view returns (bool, uint){return _bytes32ToUintMap.tryGet(key);}function get(bytes32 key) external view returns (uint) {return _bytes32ToUintMap.get(key);}function get(bytes32 key, string memory errorMessage) external view returns (uint) {return _bytes32ToUintMap.get(key, errorMessage);}
}

全部foundry测试合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/structs/EnumerableMap.t.sol

2. 代码精读

2.1 Bytes32ToBytes32Map体系

结构体Bytes32ToBytes32Map是由一个存储key值的EnumerableSet.Bytes32Set和一个存储value值的mapping(bytes32 => bytes32)构成:

		// key: bytes32类型 value:bytes32类型struct Bytes32ToBytes32Map {// 利用EnumerableSet.Bytes32Set来存储全部keys// ps:EnumerableSet库详解见:https://learnblockchain.cn/article/6272EnumerableSet.Bytes32Set _keys;// 通过key来映射value的mappingmapping(bytes32 => bytes32) _values;}
2.1.1 set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) && remove(Bytes32ToBytes32Map storage map, bytes32 key)
  • set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value):增添或更新键值对。如果输入key为已存在key(为更新键值对),返回false;如果输入key不存在(为新增键值对),返回true。时间复杂度为O(1);

  • remove(Bytes32ToBytes32Map storage map, bytes32 key):删除键值对。如果输入key为已存在key(删除键值对),返回true;如果输入key不存在,返回false。时间复杂度为O(1)。

    function set(Bytes32ToBytes32Map storage map,bytes32 key,bytes32 value) internal returns (bool) {// Bytes32ToBytes32Map._values中更新key-valuemap._values[key] = value;//调用EnumerableSet库中对应的add()方法,在EnumerableSet.Bytes32Set中增添key。如果该key已存在于set中,返回false。否则返回truereturn map._keys.add(key);}function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {// Bytes32ToBytes32Map._values中删除key-valuedelete map._values[key];// 调用EnumerableSet库中对应的remove()方法,从EnumerableSet.Bytes32Set中删除key。如果该key已存在于set中,返回true。否则返回falsereturn map._keys.remove(key);}
2.1.2 contains(Bytes32ToBytes32Map storage map, bytes32 key) && length(Bytes32ToBytes32Map storage map) && at(Bytes32ToBytes32Map storage map, uint256 index)
  • contains(Bytes32ToBytes32Map storage map, bytes32 key):查询输入key是否存在于Bytes32ToBytes32Map中。如果输入key为已存在key,返回true;如果输入key不存在,返回false。时间复杂度为O(1);
  • length(Bytes32ToBytes32Map storage map):返回Bytes32ToBytes32Map中已存在的键值对数量。时间复杂度为O(1);
  • at(Bytes32ToBytes32Map storage map, uint256 index):返回Bytes32ToBytes32Map中索引为index的key和对应的value。函数内部没有对index是否越界进行检查,所以在调用时请确保传入的index小于整个Bytes32ToBytes32Map的长度。时间复杂度为O(1)。注:index其实是指Bytes32ToBytes32Map.Bytes32Set的key的index。当每次进行key的remove操作时,set中的key顺序都会发生变化。所以不要盲目地认为该index就是键值对的添加顺序的index。
    function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {// 调用EnumerableSet库中对应的contains()方法,从EnumerableSet.Bytes32Set中查询输入key是否存在。如果该key已存在于set中,返回true。否则返回falsereturn map._keys.contains(key);}function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {// 调用EnumerableSet库中对应的length()方法,返回已存在于map中的key的数量。key的数量其实就是map中键值对的数量return map._keys.length();}function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {// 调用EnumerableSet库中对应的at()方法,返回已存在于set中对应index位置的keybytes32 key = map._keys.at(index);// 返回key,并通过key找到对应的value一起返回return (key, map._values[key]);}
2.1.3 tryGet(Bytes32ToBytes32Map storage map, bytes32 key) && get(Bytes32ToBytes32Map storage map, bytes32 key) && get(Bytes32ToBytes32Map storage map, bytes32 key, string memory errorMessage)
  • tryGet(Bytes32ToBytes32Map storage map, bytes32 key):返回输入key是否存在于Bytes32ToBytes32Map中及输入key对应的value。时间复杂度为O(1)。注:如果key不存在于Bytes32ToBytes32Map中,不会revert,而是第一个参数返回false且对应值为bytes32(0);
  • get(Bytes32ToBytes32Map storage map, bytes32 key):返回输入key对应的value。时间复杂度为O(1)。注:如果key不存在于Bytes32ToBytes32Map中,会revert;
  • get(Bytes32ToBytes32Map storage map, bytes32 key, string memory errorMessage):返回输入key对应的value(已弃用)。时间复杂度为O(1)。注:该方法与上面的get方法功能完全一致,只是本方法提供自定义revert msg的功能。但是不建议使用该方法,因为字符串参数会增加额外的memory的消耗。如果当key不存在时一定要使用自定义revert msg,建议使用tryGet()进行组合。
    function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {// 通过key找到valuebytes32 value = map._values[key];// 如果value为0,可能存在两种情况:1. 已存在key对应的value就是0、2. key不存在if (value == bytes32(0)) {// 返回该key是否存在于map中和0值return (contains(map, key), bytes32(0));} else {// 如果value不为0说明该key存在于map中,返回true和对应value值return (true, value);}}function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {// 通过key找到valuebytes32 value = map._values[key];// 如果value为0且map中不包含该key,直接revertrequire(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");// 返回value值return value;}function get(Bytes32ToBytes32Map storage map,bytes32 key,string memory errorMessage) internal view returns (bytes32) {// 通过key找到valuebytes32 value = map._values[key];// 如果value为0且map中不包含该key,直接以传入的errorMessage revertrequire(value != 0 || contains(map, key), errorMessage);// 返回value值return value;}
2.1.4 foundry代码验证
contract EnumerableMapTest is Test {MockBytes32ToBytes32Map mbtbm = new MockBytes32ToBytes32Map();function test_Bytes32ToBytes32Map_Operations() external {// emptyassertEq(mbtbm.length(), 0);assertFalse(mbtbm.contains(0));// setassertTrue(mbtbm.set(0, 'v_0'));assertEq(mbtbm.length(), 1);assertTrue(mbtbm.set('a', 'v_a'));assertEq(mbtbm.length(), 2);// set key 'a' againassertFalse(mbtbm.set('a', 'v_a_new'));assertEq(mbtbm.length(), 2);(bytes32 key, bytes32 value) = mbtbm.at(0);assertEq(0, key);assertEq('v_0', value);(key, value) = mbtbm.at(1);assertEq('a', key);assertEq('v_a_new', value);assertTrue(mbtbm.set('b', 'v_b'));assertTrue(mbtbm.set('c', 'v_c'));assertEq(mbtbm.length(), 4);// remove// key array: [0,'a','b','c']assertTrue(mbtbm.contains('a'));assertTrue(mbtbm.remove('a'));assertFalse(mbtbm.contains('a'));assertEq(mbtbm.length(), 3);// remove key 'a' againassertFalse(mbtbm.remove('a'));assertEq(mbtbm.length(), 3);// key array after remove: [0,'c','b'](key, value) = mbtbm.at(0);assertEq(0, key);assertEq('v_0', value);(key, value) = mbtbm.at(1);assertEq('c', key);assertEq('v_c', value);(key, value) = mbtbm.at(2);assertEq('b', key);assertEq('v_b', value);// check tryGet()/get()/get() with error msgbytes32[3] memory keys = [bytes32(0), 'b', 'c'];bytes32[3] memory values = [bytes32('v_0'), 'v_b', 'v_c'];// case 1: key existsbool exist;for (uint i; i < 3; ++i) {// tryGet()(exist, value) = mbtbm.tryGet(keys[i]);assertTrue(exist);assertEq(value, values[i]);// get()assertEq(mbtbm.get(keys[i]), values[i]);// get() with error msgassertEq(mbtbm.get(keys[i], "revert msg: key not exist"), values[i]);}// case 2: key doesn't existbytes32 keyNotExist = 'key not exist';(exist, value) = mbtbm.tryGet(keyNotExist);assertFalse(exist);assertEq(value, 0);// get()vm.expectRevert("EnumerableMap: nonexistent key");mbtbm.get(keyNotExist);// get() with error msgvm.expectRevert("revert msg: key not exist");mbtbm.get(keyNotExist, "revert msg: key not exist");// revert if out of boundsvm.expectRevert();mbtbm.at(1024);}
}

2.2 UintToUintMap体系

结构体UintToUintMap的内部直接封装了一个Bytes32ToBytes32Map:

	// key: uint256类型 value:uint256类型struct UintToUintMap {// 内部直接封装了一个Bytes32ToBytes32MapBytes32ToBytes32Map _inner;}
2.2.1 set(UintToUintMap storage map, uint256 key, uint256 value) && remove(UintToUintMap storage map, uint256 key)
  • set(UintToUintMap storage map, uint256 key, uint256 value):增添或更新键值对。如果输入key为已存在key(为更新键值对),返回false;如果输入key不存在(为新增键值对),返回true。时间复杂度为O(1);

  • remove(UintToUintMap storage map, uint256 key):删除键值对。如果输入key为已存在key(删除键值对),返回true;如果输入key不存在,返回false。时间复杂度为O(1)。

    function set(UintToUintMap storage map,uint256 key,uint256 value) internal returns (bool) {// 将传入的key和value都转成bytes32类型并调用底层的Bytes32ToBytes32Map的set()方法return set(map._inner, bytes32(key), bytes32(value));}function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的remove()方法return remove(map._inner, bytes32(key));}
2.2.2 contains(UintToUintMap storage map, uint256 key) && length(UintToUintMap storage map) && at(UintToUintMap storage map, uint256 index)
  • contains(UintToUintMap storage map, uint256 key):查询输入key是否存在于UintToUintMap中。如果输入key为已存在key,返回true;如果输入key不存在,返回false。时间复杂度为O(1);
  • length(UintToUintMap storage map): 返回UintToUintMap中已存在的键值对数量。时间复杂度为O(1);
  • at(UintToUintMap storage map, uint256 index):返回UintToUintMap中索引为index的key和对应的value。函数内部没有对index是否越界进行检查,所以在调用时请确保传入的index小于整个UintToUintMap的长度。时间复杂度为O(1)。注:index其实是指Bytes32ToBytes32Map.Bytes32Set的key的index。当每次进行key的remove操作时,set中的key顺序都会发生变化。所以不要盲目地认为该index就是键值对的添加顺序的index。
    function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的contains()方法return contains(map._inner, bytes32(key));}function length(UintToUintMap storage map) internal view returns (uint256) {// 调用底层的Bytes32ToBytes32Map的length()方法return length(map._inner);}function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {// 调用底层的Bytes32ToBytes32Map的at()方法,得到底层返回的bytes32类型的key和value值(bytes32 key, bytes32 value) = at(map._inner, index);// 将bytes32类型的key和value转换成uint256类型并返回return (uint256(key), uint256(value));}
2.2.3 tryGet(UintToUintMap storage map, uint256 key) && get(UintToUintMap storage map, uint256 key) && get(UintToUintMap storage map, uint256 key, string memory errorMessage)
  • tryGet(UintToUintMap storage map, uint256 key):返回输入key是否存在于UintToUintMap中及输入key对应的value。时间复杂度为O(1)。注:如果key不存在于UintToUintMap中,不会revert,而是第一个参数返回false且对应值为uint256(0);
  • get(UintToUintMap storage map, uint256 key):返回输入key对应的value。时间复杂度为O(1)。注:如果key不存在于UintToUintMap中,会revert;
  • get(UintToUintMap storage map, uint256 key, string memory errorMessage):返回输入key对应的value(已弃用)。时间复杂度为O(1)。注:该方法与上面的get方法功能完全一致,只是本方法提供自定义revert msg的功能。但是不建议使用该方法,因为字符串参数会增加额外的memory的消耗。如果当key不存在时一定要使用自定义revert msg,建议使用tryGet()进行组合。
    function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的tryGet()方法(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));// 将底层返回的传入key是否存在及bytes32类型的value转换成uint256类型返回return (success, uint256(value));}function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成uint256类型返回return uint256(get(map._inner, bytes32(key)));}function get(UintToUintMap storage map,uint256 key,string memory errorMessage) internal view returns (uint256) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成uint256类型返回return uint256(get(map._inner, bytes32(key), errorMessage));}
2.2.4 foundry代码验证
contract EnumerableMapTest is Test {MockUintToUintMap mutum = new MockUintToUintMap();function test_UintToUintMap_Operations() external {// emptyassertEq(mutum.length(), 0);assertFalse(mutum.contains(0));// setassertTrue(mutum.set(0, 1));assertEq(mutum.length(), 1);assertTrue(mutum.set(1, 2));assertEq(mutum.length(), 2);// set key 1 againassertFalse(mutum.set(1, 2 + 1));assertEq(mutum.length(), 2);(uint key, uint value) = mutum.at(0);assertEq(0, key);assertEq(1, value);(key, value) = mutum.at(1);assertEq(1, key);assertEq(3, value);assertTrue(mutum.set(2, 4));assertTrue(mutum.set(3, 8));assertEq(mutum.length(), 4);// remove// key array: [0,1,2,3]assertTrue(mutum.contains(1));assertTrue(mutum.remove(1));assertFalse(mutum.contains(1));assertEq(mutum.length(), 3);// remove key 1 againassertFalse(mutum.remove(1));assertEq(mutum.length(), 3);// key array after remove: [0,3,2](key, value) = mutum.at(0);assertEq(0, key);assertEq(1, value);(key, value) = mutum.at(1);assertEq(3, key);assertEq(8, value);(key, value) = mutum.at(2);assertEq(2, key);assertEq(4, value);// check tryGet()/get()/get() with error msguint[3] memory keys = [uint(0), 2, 3];uint[3] memory values = [uint(1), 4, 8];// case 1: key existsbool exist;for (uint i; i < 3; ++i) {// tryGet()(exist, value) = mutum.tryGet(keys[i]);assertTrue(exist);assertEq(value, values[i]);// get()assertEq(mutum.get(keys[i]), values[i]);// get() with error msgassertEq(mutum.get(keys[i], "revert msg: key not exist"), values[i]);}// case 2: key doesn't existuint keyNotExist = 1024;(exist, value) = mutum.tryGet(keyNotExist);assertFalse(exist);assertEq(value, 0);// get()vm.expectRevert("EnumerableMap: nonexistent key");mutum.get(keyNotExist);// get() with error msgvm.expectRevert("revert msg: key not exist");mutum.get(keyNotExist, "revert msg: key not exist");// revert if out of boundsvm.expectRevert();mutum.at(1024);}
}

2.3 UintToAddressMap体系

结构体UintToAddressMap的内部直接封装了一个Bytes32ToBytes32Map:

	// key: uint256类型 value:address类型struct UintToAddressMap {// 内部直接封装了一个Bytes32ToBytes32MapBytes32ToBytes32Map _inner;}
2.3.1 set(UintToAddressMap storage map, uint256 key, address value) && remove(UintToAddressMap storage map, uint256 key)
  • set(UintToAddressMap storage map, uint256 key, address value):增添或更新键值对。如果输入key为已存在key(为更新键值对),返回false;如果输入key不存在(为新增键值对),返回true。时间复杂度为O(1);

  • remove(UintToAddressMap storage map, uint256 key):删除键值对。如果输入key为已存在key(删除键值对),返回true;如果输入key不存在,返回false。时间复杂度为O(1)。

    function set(UintToAddressMap storage map,uint256 key,address value) internal returns (bool) {// 将传入的key和value都转成bytes32类型并调用底层的Bytes32ToBytes32Map的set()方法return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));}function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的remove()方法return remove(map._inner, bytes32(key));}
2.3.2 contains(UintToAddressMap storage map, uint256 key) && length(UintToAddressMap storage map) && at(UintToAddressMap storage map, uint256 index)
  • contains(UintToAddressMap storage map, uint256 key):查询输入key是否存在于UintToAddressMap中。如果输入key为已存在key,返回true;如果输入key不存在,返回false。时间复杂度为O(1);
  • length(UintToAddressMap storage map):返回UintToAddressMap中已存在的键值对数量。时间复杂度为O(1);
  • at(UintToAddressMap storage map, uint256 index):返回UintToAddressMap中索引为index的key和对应的value。函数内部没有对index是否越界进行检查,所以在调用时请确保传入的index小于整个UintToAddressMap的长度。时间复杂度为O(1)。注:index其实是指Bytes32ToBytes32Map.Bytes32Set的key的index。当每次进行key的remove操作时,set中的key顺序都会发生变化。所以不要盲目地认为该index就是键值对的添加顺序的index。
    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的contains()方法return contains(map._inner, bytes32(key));}function length(UintToAddressMap storage map) internal view returns (uint256) {// 调用底层的Bytes32ToBytes32Map的length()方法return length(map._inner);}function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {// 调用底层的Bytes32ToBytes32Map的at()方法,得到底层返回的bytes32类型的key和value值(bytes32 key, bytes32 value) = at(map._inner, index);// 将bytes32类型的key和value分别转换成uint256和address类型并返回return (uint256(key), address(uint160(uint256(value))));}
2.3.3 tryGet(UintToAddressMap storage map, uint256 key) && get(UintToAddressMap storage map, uint256 key) && get(UintToAddressMap storage map, uint256 key, string memory errorMessage)
  • tryGet(UintToAddressMap storage map, uint256 key):返回输入key是否存在于UintToAddressMap中及输入key对应的value。时间复杂度为O(1)。注:如果key不存在于UintToAddressMap中,不会revert,而是第一个参数返回false且对应值为address(0);
  • get(UintToAddressMap storage map, uint256 key):返回输入key对应的value。时间复杂度为O(1)。注:如果key不存在于UintToAddressMap中,会revert;
  • get(UintToAddressMap storage map, uint256 key, string memory errorMessage):返回输入key对应的value(已弃用)。时间复杂度为O(1)。注:该方法与上面的get方法功能完全一致,只是本方法提供自定义revert msg的功能。但是不建议使用该方法,因为字符串参数会增加额外的memory的消耗。如果当key不存在时一定要使用自定义revert msg,建议使用tryGet()进行组合。
    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的tryGet()方法(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));// 将底层返回的传入key是否存在及bytes32类型的value转换成address类型返回return (success, address(uint160(uint256(value))));}function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成address类型返回return address(uint160(uint256(get(map._inner, bytes32(key)))));}function get(UintToAddressMap storage map,uint256 key,string memory errorMessage) internal view returns (address) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成address类型返回return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));}
2.3.4 foundry代码验证
contract EnumerableMapTest is Test {MockUintToAddressMap mutam = new MockUintToAddressMap();function test_UintToAddressMap_Operations() external {// emptyassertEq(mutam.length(), 0);assertFalse(mutam.contains(0));// setassertTrue(mutam.set(0, address(0)));assertEq(mutam.length(), 1);assertTrue(mutam.set(1, address(1)));assertEq(mutam.length(), 2);// set key 1 againassertFalse(mutam.set(1, address(1 + 1)));assertEq(mutam.length(), 2);(uint key, address value) = mutam.at(0);assertEq(0, key);assertEq(address(0), value);(key, value) = mutam.at(1);assertEq(1, key);assertEq(address(2), value);assertTrue(mutam.set(2, address(2)));assertTrue(mutam.set(3, address(3)));assertEq(mutam.length(), 4);// remove// key array: [0,1,2,3]assertTrue(mutam.contains(1));assertTrue(mutam.remove(1));assertFalse(mutam.contains(1));assertEq(mutam.length(), 3);// remove key 1 againassertFalse(mutam.remove(1));assertEq(mutam.length(), 3);// key array after remove: [0,3,2](key, value) = mutam.at(0);assertEq(0, key);assertEq(address(0), value);(key, value) = mutam.at(1);assertEq(3, key);assertEq(address(3), value);(key, value) = mutam.at(2);assertEq(2, key);assertEq(address(2), value);// check tryGet()/get()/get() with error msguint[3] memory keys = [uint(0), 2, 3];address[3] memory values = [address(0), address(2), address(3)];// case 1: key existsbool exist;for (uint i; i < 3; ++i) {// tryGet()(exist, value) = mutam.tryGet(keys[i]);assertTrue(exist);assertEq(value, values[i]);// get()assertEq(mutam.get(keys[i]), values[i]);// get() with error msgassertEq(mutam.get(keys[i], "revert msg: key not exist"), values[i]);}// case 2: key doesn't existuint keyNotExist = 1024;(exist, value) = mutam.tryGet(keyNotExist);assertFalse(exist);assertEq(value, address(0));// get()vm.expectRevert("EnumerableMap: nonexistent key");mutam.get(keyNotExist);// get() with error msgvm.expectRevert("revert msg: key not exist");mutam.get(keyNotExist, "revert msg: key not exist");// revert if out of boundsvm.expectRevert();mutam.at(1024);}
}

2.4 AddressToUintMap体系

结构体AddressToUintMap的内部直接封装了一个Bytes32ToBytes32Map:

	// key: address类型 value:uint256类型struct AddressToUintMap {// 内部直接封装了一个Bytes32ToBytes32MapBytes32ToBytes32Map _inner;}
2.4.1 set(AddressToUintMap storage map, address key, uint256 value) && remove(AddressToUintMap storage map, address key)
  • set(AddressToUintMap storage map, address key, uint256 value):增添或更新键值对。如果输入key为已存在key(为更新键值对),返回false;如果输入key不存在(为新增键值对),返回true。时间复杂度为O(1);

  • remove(AddressToUintMap storage map, address key):删除键值对。如果输入key为已存在key(删除键值对),返回true;如果输入key不存在,返回false。时间复杂度为O(1)。

    function set(AddressToUintMap storage map,address key,uint256 value) internal returns (bool) {// 将传入的key和value都转成bytes32类型并调用底层的Bytes32ToBytes32Map的set()方法return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));}function remove(AddressToUintMap storage map, address key) internal returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的remove()方法return remove(map._inner, bytes32(uint256(uint160(key))));}
2.4.2 contains(AddressToUintMap storage map, address key) && length(AddressToUintMap storage map) && at(AddressToUintMap storage map, uint256 index)
  • contains(AddressToUintMap storage map, address key):查询输入key是否存在于AddressToUintMap中。如果输入key为已存在key,返回true;如果输入key不存在,返回false。时间复杂度为O(1);
  • length(AddressToUintMap storage map):返回AddressToUintMap中已存在的键值对数量。时间复杂度为O(1);
  • at(AddressToUintMap storage map, uint256 index):返回AddressToUintMap中索引为index的key和对应的value。函数内部没有对index是否越界进行检查,所以在调用时请确保传入的index小于整个UintToAddressMap的长度。时间复杂度为O(1)。注:index其实是指Bytes32ToBytes32Map.Bytes32Set的key的index。当每次进行key的remove操作时,set中的key顺序都会发生变化。所以不要盲目地认为该index就是键值对的添加顺序的index。
    function contains(AddressToUintMap storage map, address key) internal view returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的contains()方法return contains(map._inner, bytes32(uint256(uint160(key))));}function length(AddressToUintMap storage map) internal view returns (uint256) {// 调用底层的Bytes32ToBytes32Map的length()方法return length(map._inner);}function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {// 调用底层的Bytes32ToBytes32Map的at()方法,得到底层返回的bytes32类型的key和value值(bytes32 key, bytes32 value) = at(map._inner, index);// 将bytes32类型的key和value分别转换成address和uint256类型并返回return (address(uint160(uint256(key))), uint256(value));}
2.4.3 tryGet(AddressToUintMap storage map, address key) && get(AddressToUintMap storage map, address key) && get(AddressToUintMap storage map, address key, string memory errorMessage)
  • tryGet(AddressToUintMap storage map, address key):返回输入key是否存在于AddressToUintMap中及输入key对应的value。时间复杂度为O(1)。注:如果key不存在于AddressToUintMap中,不会revert,而是第一个参数返回false且对应值为uint256(0);
  • get(AddressToUintMap storage map, address key):返回输入key对应的value。时间复杂度为O(1)。注:如果key不存在于AddressToUintMap中,会revert;
  • get(AddressToUintMap storage map, address key, string memory errorMessage):返回输入key对应的value(已弃用)。时间复杂度为O(1)。注:该方法与上面的get方法功能完全一致,只是本方法提供自定义revert msg的功能。但是不建议使用该方法,因为字符串参数会增加额外的memory的消耗。如果当key不存在时一定要使用自定义revert msg,建议使用tryGet()进行组合。
    function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的tryGet()方法(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));// 将底层返回的传入key是否存在及bytes32类型的value转换成uint256类型返回return (success, uint256(value));}function get(AddressToUintMap storage map, address key) internal view returns (uint256) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成uint256类型返回return uint256(get(map._inner, bytes32(uint256(uint160(key)))));}function get(AddressToUintMap storage map,address key,string memory errorMessage) internal view returns (uint256) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成uint256类型返回return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));}
2.4.4 foundry代码验证
contract EnumerableMapTest is Test {MockAddressToUintMap matum = new MockAddressToUintMap();function test_AddressToUintMap_Operations() external {// emptyassertEq(matum.length(), 0);assertFalse(matum.contains(address(0)));// setassertTrue(matum.set(address(0), 0));assertEq(matum.length(), 1);assertTrue(matum.set(address(1), 1));assertEq(matum.length(), 2);// set key address(1) againassertFalse(matum.set(address(1), 1 + 1));assertEq(matum.length(), 2);(address key, uint value) = matum.at(0);assertEq(address(0), key);assertEq(0, value);(key, value) = matum.at(1);assertEq(address(1), key);assertEq(2, value);assertTrue(matum.set(address(2), 2));assertTrue(matum.set(address(3), 3));assertEq(matum.length(), 4);// remove// key array: [address(0),address(1),address(2),address(3)]assertTrue(matum.contains(address(1)));assertTrue(matum.remove(address(1)));assertFalse(matum.contains(address(1)));assertEq(matum.length(), 3);// remove key address(1) againassertFalse(matum.remove(address(1)));assertEq(matum.length(), 3);// key array after remove: [address(0),address(3),address(2)](key, value) = matum.at(0);assertEq(address(0), key);assertEq(0, value);(key, value) = matum.at(1);assertEq(address(3), key);assertEq(3, value);(key, value) = matum.at(2);assertEq(address(2), key);assertEq(2, value);// check tryGet()/get()/get() with error msgaddress[3] memory keys = [address(0), address(2), address(3)];uint[3] memory values = [uint(0), 2, 3];// case 1: key existsbool exist;for (uint i; i < 3; ++i) {// tryGet()(exist, value) = matum.tryGet(keys[i]);assertTrue(exist);assertEq(value, values[i]);// get()assertEq(matum.get(keys[i]), values[i]);// get() with error msgassertEq(matum.get(keys[i], "revert msg: key not exist"), values[i]);}// case 2: key doesn't existaddress keyNotExist = address(1024);(exist, value) = matum.tryGet(keyNotExist);assertFalse(exist);assertEq(value, 0);// get()vm.expectRevert("EnumerableMap: nonexistent key");matum.get(keyNotExist);// get() with error msgvm.expectRevert("revert msg: key not exist");matum.get(keyNotExist, "revert msg: key not exist");// revert if out of boundsvm.expectRevert();matum.at(1024);}
}

2.5 Bytes32ToUintMap体系

结构体Bytes32ToUintMap的内部直接封装了一个Bytes32ToBytes32Map:

	// key: bytes32类型 value:uint256类型struct Bytes32ToUintMap {// 内部直接封装了一个Bytes32ToBytes32MapBytes32ToBytes32Map _inner;}
2.5.1 set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) && remove(Bytes32ToUintMap storage map, bytes32 key)
  • set(Bytes32ToUintMap storage map, bytes32 key, uint256 value):增添或更新键值对。如果输入key为已存在key(为更新键值对),返回false;如果输入key不存在(为新增键值对),返回true。时间复杂度为O(1);

  • remove(Bytes32ToUintMap storage map, bytes32 key):删除键值对。如果输入key为已存在key(删除键值对),返回true;如果输入key不存在,返回false。时间复杂度为O(1)。

    function set(Bytes32ToUintMap storage map,bytes32 key,uint256 value) internal returns (bool) {// 将传入的key和value都转成bytes32类型并调用底层的Bytes32ToBytes32Map的set()方法return set(map._inner, key, bytes32(value));}function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {// 将传入的key转成bytes32类型并调用底层的Bytes32ToBytes32Map的remove()方法return remove(map._inner, key);}
2.5.2 contains(Bytes32ToUintMap storage map, bytes32 key) && length(Bytes32ToUintMap storage map) && at(Bytes32ToUintMap storage map, uint256 index)
  • contains(Bytes32ToUintMap storage map, bytes32 key):查询输入key是否存在于Bytes32ToUintMap中。如果输入key为已存在key,返回true;如果输入key不存在,返回false。时间复杂度为O(1);
  • length(Bytes32ToUintMap storage map):返回Bytes32ToUintMap中已存在的键值对数量。时间复杂度为O(1);
  • at(Bytes32ToUintMap storage map, uint256 index):返回Bytes32ToUintMap中索引为index的key和对应的value。函数内部没有对index是否越界进行检查,所以在调用时请确保传入的index小于整个Bytes32ToUintMap的长度。时间复杂度为O(1)。注:index其实是指Bytes32ToBytes32Map.Bytes32Set的key的index。当每次进行key的remove操作时,set中的key顺序都会发生变化。所以不要盲目地认为该index就是键值对的添加顺序的index。
    function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {// 直接调用底层的Bytes32ToBytes32Map的contains()方法return contains(map._inner, key);}function length(Bytes32ToUintMap storage map) internal view returns (uint256) {// 调用底层的Bytes32ToBytes32Map的length()方法return length(map._inner);}function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {// 调用底层的Bytes32ToBytes32Map的at()方法,得到底层返回的bytes32类型的key和value值(bytes32 key, bytes32 value) = at(map._inner, index);// 直接返回key,并将value转换成uint256类型返回return (key, uint256(value));}
2.5.3 tryGet(Bytes32ToUintMap storage map, bytes32 key) && get(Bytes32ToUintMap storage map, bytes32 key) && get(Bytes32ToUintMap storage map, bytes32 key, string memory errorMessage)
  • tryGet(Bytes32ToUintMap storage map, bytes32 key):返回输入key是否存在于Bytes32ToUintMap中及输入key对应的value。时间复杂度为O(1)。注:如果key不存在于Bytes32ToUintMap中,不会revert,而是第一个参数返回false且对应值为uint256(0);
  • get(Bytes32ToUintMap storage map, bytes32 key):返回输入key对应的value。时间复杂度为O(1)。注:如果key不存在于Bytes32ToUintMap中,会revert;
  • get(Bytes32ToUintMap storage map, bytes32 key, string memory errorMessage):返回输入key对应的value(已弃用)。时间复杂度为O(1)。注:该方法与上面的get方法功能完全一致,只是本方法提供自定义revert msg的功能。但是不建议使用该方法,因为字符串参数会增加额外的memory的消耗。如果当key不存在时一定要使用自定义revert msg,建议使用tryGet()进行组合。
    function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {// 直接调用底层的Bytes32ToBytes32Map的tryGet()方法(bool success, bytes32 value) = tryGet(map._inner, key);// 直接返回key是否存在,并将value转换成uint256类型返回return (success, uint256(value));}function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {// 直接调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成uint256类型返回return uint256(get(map._inner, key));}function get(Bytes32ToUintMap storage map,bytes32 key,string memory errorMessage) internal view returns (uint256) {// 直接调用底层的Bytes32ToBytes32Map的get()方法,得到的bytes32类型结果转换成uint256类型返回return uint256(get(map._inner, key, errorMessage));}
2.5.4 foundry代码验证
contract EnumerableMapTest is Test {MockBytes32ToUintMap mbtum = new MockBytes32ToUintMap();function test_Bytes32ToUintMap_Operations() external {// emptyassertEq(mbtum.length(), 0);assertFalse(mbtum.contains(0));// setassertTrue(mbtum.set(0, 0));assertEq(mbtum.length(), 1);assertTrue(mbtum.set('a', 1));assertEq(mbtum.length(), 2);// set key 'a' againassertFalse(mbtum.set('a', 97));assertEq(mbtum.length(), 2);(bytes32 key, uint value) = mbtum.at(0);assertEq(0, key);assertEq(0, value);(key, value) = mbtum.at(1);assertEq('a', key);assertEq(97, value);assertTrue(mbtum.set('b', 98));assertTrue(mbtum.set('c', 99));assertEq(mbtum.length(), 4);// remove// key array: [0,'a','b','c']assertTrue(mbtum.contains('a'));assertTrue(mbtum.remove('a'));assertFalse(mbtum.contains('a'));assertEq(mbtum.length(), 3);// remove key 'a' againassertFalse(mbtum.remove('a'));assertEq(mbtum.length(), 3);// key array after remove: [0,'c','b'](key, value) = mbtum.at(0);assertEq(0, key);assertEq(0, value);(key, value) = mbtum.at(1);assertEq('c', key);assertEq(99, value);(key, value) = mbtum.at(2);assertEq('b', key);assertEq(98, value);// check tryGet()/get()/get() with error msgbytes32[3] memory keys = [bytes32(0), 'b', 'c'];uint[3] memory values = [uint(0), 98, 99];// case 1: key existsbool exist;for (uint i; i < 3; ++i) {// tryGet()(exist, value) = mbtum.tryGet(keys[i]);assertTrue(exist);assertEq(value, values[i]);// get()assertEq(mbtum.get(keys[i]), values[i]);// get() with error msgassertEq(mbtum.get(keys[i], "revert msg: key not exist"), values[i]);}// case 2: key doesn't existbytes32 keyNotExist = 'key not exist';(exist, value) = mbtum.tryGet(keyNotExist);assertFalse(exist);assertEq(value, 0);// get()vm.expectRevert("EnumerableMap: nonexistent key");mbtum.get(keyNotExist);// get() with error msgvm.expectRevert("revert msg: key not exist");mbtum.get(keyNotExist, "revert msg: key not exist");// revert if out of boundsvm.expectRevert();mbtum.at(1024);}
}

ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!

在这里插入图片描述

公众号名称:后现代泼痞浪漫主义奠基人

相关文章:

Michael.W基于Foundry精读Openzeppelin第20期——EnumerableMap.sol

0. 版本 [openzeppelin]&#xff1a;v4.8.3&#xff0c;[forge-std]&#xff1a;v1.5.6 0.1 EnumerableMap.sol Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/structs/EnumerableMap.sol EnumerableMap库提供了Bytes32ToB…...

深入探索二叉树:应用、计算和遍历

当涉及到二叉树的计算问题时&#xff0c;我们可以进一步介绍如何计算叶子节点数、树的宽度和叶子的深度&#xff0c;并解释三种常见的二叉树遍历方式&#xff1a;先序遍历、中序遍历和后序遍历。 1. 计算叶子节点数 叶子节点是指没有子节点的节点&#xff0c;也就是树中的末端…...

关于 1 + 1 = 2 的证明

1 1 2 首先是皮亚诺的自然数公理 意大利数学家皮亚诺提出的关于自然数的 5 5 5 条公理如下&#xff08;定义 S ( x ) S(x) S(x) 为自然数 x x x 的后继&#xff09;&#xff1a; 0 0 0 是自然数每一个自然数 n n n 都有一个自然数后继记为 S ( n ) S(n) S(n) 0 0 0 不是…...

【C++】——内存管理

目录 回忆C语言内存管理C内存管理方式new deleteoperator new与operator delete函数new和delete的实现原理定位new表达式(placement-new)malloc/free和new/delete的区别 回忆C语言内存管理 void Test() {int* p1 (int*)malloc(sizeof(int));free(p1);int* p2 (int*)calloc(4…...

Jmeter录制HTTPS脚本

Jmeter录制HTTPS脚本 文章目录 添加“HTTP代理服务器”设置浏览器代理证书导入存在问题 添加“HTTP代理服务器” 设置浏览器代理 保持端口一致 证书导入 点击一下启动让jmeter自动生成证书&#xff0c;放在bin目录下&#xff1a; 打开jmeter的SSL管理器选择刚刚生成的证书&…...

Linux 的Centos 7 安装 启动 Google Chrome

我之所以在Centos上安装Chrome主要是为了让Web自动化测试工具可以启动Chrome&#xff0c;协助我做一些工作。 参考&#xff1a;centos7 google-chrome的安装与启动 - 简书 1.安装chrome逻辑 1. 下载安装包 2. 安装 3. 启动 》这就是在window上的逻辑&#xff0c;只是用命令行…...

DNS WEB HTTP

DNS与域名 网络是基于 TCP/IP 协议进行通信和连接的。 每一台主机都有唯一的标识&#xff0c;用于区别在网络上成千上万个用户和计算机。即固定的IP地址&#xff08;32位二进制数转换成为十进制数——点分十进制&#xff09;。每一个与网络相连接的计算机和服务器都被指派一个…...

微信小程序animation动画,微信小程序animation动画无限循环播放

需求是酱紫的&#xff1a; 页面顶部的喇叭通知&#xff0c;内容不固定&#xff0c;宽度不固定&#xff0c;就是做走马灯&#xff08;轮播&#xff09;效果&#xff0c;从左到右的走马灯&#xff08;轮播&#xff09;&#xff0c;每播放一遍暂停 1500ms &#xff5e; 2000ms 刚…...

node.js

什么是Node.js Node.js 是一个免费的、开源的、跨平台的 JavaScript 运行时环境,使开发者可以搭建服务器端的JavaScript应用程序 概念: 使用Node.js编写后端程序 // 支持前端工程化 ​ 后端程序&#xff1a;提供接口和数据 &#xff0c;网页资源 ​ 前端工程化:对代码压缩&…...

【微信小程序创作之路】- 小程序远程数据请求、获取个人信息

【微信小程序创作之路】- 小程序远程数据请求、获取个人信息 第七章 小程序远程数据请求、获取个人信息 文章目录 【微信小程序创作之路】- 小程序远程数据请求、获取个人信息前言一、远程数据请求1.本地环境2.正式域名 二、获取用户个人信息1.展示当前用户的身份信息2.获取用…...

XML基础知识讲解

文章目录 1. xml简介2. xml快速入门3. xml的元素(标签)定义4. xml标签的命名规范5. xml的属性定义和注释6. 转义字符7. CDATA区8. xml的处理指令9. xml的约束 1. xml简介 XML&#xff08;eXtensible Markup Language&#xff09;是一种用于描述数据的标记语。 它以纯文本的方…...

(十二)大数据实战——hadoop集群之HDFS高可用自动故障转移

前言 本节内容主要介绍一下hadoop集群下实现HDFS高可用的自动故障转移&#xff0c;HDFS高可用的自动故障转移主要通过zookeeper实现故障的监控和主节点的切换。自动故障转移为 HDFS 部署增加了两个新组件&#xff1a;ZooKeeper 和 ZKFailoverController &#xff08;ZKFC&…...

Ubuntu下载deb包及其依赖包

一、简介 有时我们需要在离线环境使用提前准备好的deb包&#xff0c;然后只需要在新机器使用dpkg -i安装即可。 二、命令 apt-get download $(apt-rdepends &#xff08;需要下载的包&#xff0c;可以有多个&#xff09; | grep -v "^ " | sed s/debconf-2.0/debco…...

Ubuntu中解/压缩命令

一、zip文件 #解压 unzip filename.zip #压缩 zip filename.zip dirname # 递归处理&#xff0c;将指定目录下的所有文件和子目录一并压缩 zip -r filename.zip dirname 二、tar文件 # 解压 tar xvf FileName.tar # 压缩&#xff0c;将DirName和其下所有文件(夹)打包非压…...

剑指 Offer 12. 矩阵中的路径(回溯 DFS)

文章目录 题目描述思路分析完整代码 题目描述 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff…...

iceberg对比hive优势

1.事务性 从事务性上来说&#xff0c;iceberg具有更高的数据质量。 因为iceberg本质是一种table format&#xff0c;屏蔽了底层的存储细节&#xff0c;写入数据时候需要严格按照schema写入。而hive可以先写入底层数据&#xff0c;然后使用load partition的方式来加载分区。这样…...

ProgressBar基本使用

作用&#xff1a;进度条&#xff0c;用于展示某个任务的完成情况&#xff0c; 常用属性&#xff1a; 设定进度条的最大、最小值、自增步长 常用事件&#xff1a; 后台代码&#xff1a; private void progressBar1_Click(object sender, EventArgs e){Thread t;//使用线程执行…...

spring boot java使用XEasyPdf生成pdf文档

java使用XEasyPdf生成pdf文档 spring boot java使用XEasyPdf生成pdf文档第一步导入maven坐标,pom.xml全部贴上第二步编写代码代码实战&#xff1a; spring boot java使用XEasyPdf生成pdf文档 第一步导入maven坐标,pom.xml全部贴上 <?xml version"1.0" encoding…...

自定义elementui的主题

通常情况下&#xff0c;我们使用elementui框架的时候默认组件的主题都是白色的&#xff0c;比如&#xff1a; 但是如果想自定义主题&#xff0c;改变主题颜色&#xff0c;以及各种默认颜色&#xff0c;其实也不难&#xff1a; 配置默认主题&#xff0c;选好后点击下载 在vu…...

eNSP interface g0/0/0 报错解决办法

文章目录 1 报错截图2 解决办法2.1 排查设备是否有 GM 接口2.2 更换适合的路由器&#xff0c;并验证 1 报错截图 2 解决办法 2.1 排查设备是否有 GM 接口 查看下设备是否支持 GM 接口&#xff08;GigabitEthernet&#xff09; 方式一&#xff1a;右键路由器设备 - 设置 - 查看…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...