12.1 庫合約
庫合約是一種特殊的合約,為了提升solidity代碼的復(fù)用性和減少gas而存在蘑拯。庫合約一般都是一些好用的函數(shù)合集(庫函數(shù)),由大神或者項(xiàng)目方創(chuàng)作。
他和普通合約主要有以下幾點(diǎn)不同:
- 不能存在狀態(tài)變量
- 不能夠繼承或被繼承
- 不能接收以太幣
- 不可以被銷毀
12.2 庫合約的使用
- 一個(gè)簡單的例子:通過庫合約名稱調(diào)用庫函數(shù)
// 庫合約的定義
library Math { // 合約名稱大寫開頭:編碼習(xí)慣
function max(uint x, uint y) internal pure returns (uint) {
return x >= y ? x : y;
}
}
contract Test {
function testMax(uint _x, uint _y) external pure returns (uint) {
// 庫函數(shù)的使用
return Math.max(_x, _y);
}
}
定義了一個(gè)庫合約Math盛霎,實(shí)現(xiàn)一個(gè)返回兩個(gè)數(shù)中較大值的函數(shù)。一般庫合約中函數(shù)使用internal修飾耽装,如果想要外部訪問可以使用public修飾愤炸,使用external和private修飾是沒有意義的。
測(cè)試合約Test中使用Math.max對(duì)庫合約中的函數(shù)進(jìn)行調(diào)用掉奄。
- 另一個(gè)簡單的例子:利用using for指令
library ArrayLib {
function find(uint[] storage arr, uint x) internal view returns (uint) {
for (uint i = 0; i < arr.length; i++) {
if (arr[i] == x) {
return i;
}
}
revert("not found");
}
}
contract TestArray {
// 使用庫合約:using for规个,使庫合約應(yīng)用到庫函數(shù)的第一個(gè)參數(shù)uint[],uint[]就擁有了庫合約的所有功能
using ArrayLib for uint[];
uint[] public arr = [3,2,1,5,8,0];
function testFind(uint _x) external view returns (uint i) {
// return ArrayLib.find(arr, 2);
return arr.find(_x);
}
}
庫合約ArrayLib中挥萌,實(shí)現(xiàn)了一個(gè)查找數(shù)組元素索引的函數(shù)绰姻。
測(cè)試合約TestArray中使用using for語法調(diào)用庫合約的功能。指令using A for B;
可用于附加庫函數(shù)(從庫 A)到任何類型B引瀑。添加完指令后狂芋,庫A中的函數(shù)會(huì)自動(dòng)添加為B類型變量的成員,可以直接調(diào)用憨栽。
注意:在調(diào)用的時(shí)候帜矾,這個(gè)變量會(huì)被當(dāng)作第一個(gè)參數(shù)傳遞給函數(shù)
12.3 String庫合約
String庫合約是將uint256類型轉(zhuǎn)換為相應(yīng)的string類型的代碼庫,樣例代碼如下:
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) public pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) public pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) public pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
String庫合約主要包含三個(gè)函數(shù):
- toString(uint256 value):將uint256轉(zhuǎn)為string屑柔。
- toHexString(uint256 value):將uint256轉(zhuǎn)為16進(jìn)制屡萤,再轉(zhuǎn)為string。
-
toHexString(uint256 value, uint256 length):將uint256轉(zhuǎn)為固定長度的16進(jìn)制string類型掸宛。
使用示例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/Strings.sol";
contract Test {
using Strings for uint256;
function TestToString(uint256 _x) external pure returns (string memory) {
return _x.toString();
}
function TestToHexString(uint256 _x) external pure returns (string memory) {
return _x.toHexString();
}
function TestToHexString2(uint256 _x, uint256 _y) external pure returns (string memory) {
return _x.toHexString(_y);
}
}
運(yùn)行結(jié)果:
常見的庫合約舉例: