类型转换 #
一、类型转换概述 #
Solidity是静态类型语言,不同类型之间需要显式或隐式转换。
text
类型转换分类:
- 隐式转换:自动进行,安全
- 显式转换:手动进行,可能丢失精度
二、隐式转换 #
2.1 整数隐式转换 #
solidity
contract ImplicitConversion {
function demo() public pure {
// 小类型到大类型:自动转换
uint8 a = 10;
uint16 b = a; // uint8 -> uint16
uint32 c = b; // uint16 -> uint32
uint256 d = c; // uint32 -> uint256
// 有符号整数
int8 e = -5;
int16 f = e; // int8 -> int16
int256 g = f; // int16 -> int256
// 无符号到有符号(相同大小)
uint8 h = 10;
int16 i = h; // uint8 -> int16(更大类型)
}
}
2.2 隐式转换规则 #
solidity
// 规则:小类型到大类型可以隐式转换
// uint8 -> uint16 -> uint32 -> uint64 -> uint128 -> uint256
// int8 -> int16 -> int32 -> int64 -> int128 -> int256
// 允许的隐式转换
uint8 a = 1;
uint256 b = a; // ✓
// 不允许的隐式转换
// uint256 c = 1;
// uint8 d = c; // ✗ 错误:需要显式转换
2.3 地址隐式转换 #
solidity
contract AddressImplicit {
address public addr;
address payable public payableAddr;
function demo() public {
// address -> address payable
payableAddr = payable(addr); // 需要显式转换
// address payable -> address
addr = payableAddr; // 隐式转换
}
}
三、显式转换 #
3.1 整数显式转换 #
solidity
contract ExplicitConversion {
function demo() public pure {
// 大类型到小类型:显式转换(可能截断)
uint256 a = 300;
uint8 b = uint8(a); // 300 % 256 = 44
// 有符号到无符号
int256 c = -1;
uint256 d = uint256(c); // 最大uint256值
// 无符号到有符号
uint256 e = 100;
int256 f = int256(e); // 100
}
}
3.2 整数转换示例 #
solidity
contract IntegerConversion {
function truncate() public pure returns (uint8) {
uint256 large = 300; // 二进制: 100101100
uint8 small = uint8(large); // 截断后: 00101100 = 44
return small;
}
function signedToUnsigned() public pure returns (uint256) {
int256 signed = -1;
uint256 unsigned = uint256(signed);
// -1的二进制表示全为1,转换为uint256是最大值
return unsigned; // 115792089237316195423570985008687907853269984665640564039457584007913129639935
}
function unsignedToSigned() public pure returns (int256) {
uint256 unsigned = 100;
int256 signed = int256(unsigned);
return signed; // 100
}
}
3.3 地址转换 #
solidity
contract AddressConversion {
function uintToAddress(uint256 _value) public pure returns (address) {
return address(uint160(_value));
}
function addressToUint(address _addr) public pure returns (uint256) {
return uint256(uint160(_addr));
}
function bytesToAddress(bytes20 _bytes) public pure returns (address) {
return address(_bytes);
}
function addressToBytes(address _addr) public pure returns (bytes20) {
return bytes20(_addr);
}
}
3.4 字节转换 #
solidity
contract BytesConversion {
function bytes32ToBytes16(bytes32 _data) public pure returns (bytes16) {
return bytes16(_data); // 截断前16字节
}
function bytes16ToBytes32(bytes16 _data) public pure returns (bytes32) {
return bytes32(_data); // 填充到32字节
}
function uintToBytes(uint256 _value) public pure returns (bytes32) {
return bytes32(_value);
}
function bytesToUint(bytes32 _data) public pure returns (uint256) {
return uint256(_data);
}
}
四、字符串转换 #
4.1 string与bytes转换 #
solidity
contract StringBytesConversion {
function stringToBytes(string memory _str) public pure returns (bytes memory) {
return bytes(_str);
}
function bytesToString(bytes memory _data) public pure returns (string memory) {
return string(_data);
}
function getFirstChar(string memory _str) public pure returns (bytes1) {
bytes memory b = bytes(_str);
require(b.length > 0, "Empty string");
return b[0];
}
}
4.2 数字与字符串转换 #
solidity
contract NumberStringConversion {
// 使用OpenZeppelin的Strings库
using Strings for uint256;
function uintToString(uint256 _value) public pure returns (string memory) {
return _value.toString();
}
function intToString(int256 _value) public pure returns (string memory) {
if (_value >= 0) {
return uint256(_value).toString();
} else {
return string(abi.encodePacked("-", uint256(-_value).toString()));
}
}
}
4.3 地址与字符串转换 #
solidity
contract AddressStringConversion {
using Strings for address;
function addressToString(address _addr) public pure returns (string memory) {
return _addr.toHexString();
}
function stringToAddress(string memory _str) public pure returns (address) {
bytes memory b = bytes(_str);
require(b.length == 42, "Invalid address length");
require(b[0] == "0" && b[1] == "x", "Invalid prefix");
uint256 result = 0;
for (uint256 i = 2; i < 42; i++) {
uint8 c = uint8(b[i]);
uint8 value;
if (c >= 48 && c <= 57) { // 0-9
value = c - 48;
} else if (c >= 65 && c <= 70) { // A-F
value = c - 55;
} else if (c >= 97 && c <= 102) { // a-f
value = c - 87;
} else {
revert("Invalid character");
}
result = result * 16 + value;
}
return address(uint160(result));
}
}
五、ABI编码转换 #
5.1 abi.encode #
solidity
contract ABIEncode {
function encodeUint(uint256 _value) public pure returns (bytes memory) {
return abi.encode(_value);
}
function encodeMultiple(uint256 a, address b, bool c) public pure returns (bytes memory) {
return abi.encode(a, b, c);
}
function encodeArray(uint256[] memory _arr) public pure returns (bytes memory) {
return abi.encode(_arr);
}
}
5.2 abi.encodePacked #
solidity
contract ABIEncodePacked {
// 紧凑编码,不包含类型信息
function pack(string memory a, string memory b) public pure returns (bytes memory) {
return abi.encodePacked(a, b);
}
// 计算keccak256哈希
function hash(string memory a, string memory b) public pure returns (bytes32) {
return keccak256(abi.encodePacked(a, b));
}
// 拼接字符串
function concat(string memory a, string memory b) public pure returns (string memory) {
return string(abi.encodePacked(a, b));
}
}
5.3 abi.decode #
solidity
contract ABIDecode {
function decodeUint(bytes memory _data) public pure returns (uint256) {
return abi.decode(_data, (uint256));
}
function decodeMultiple(bytes memory _data) public pure returns (uint256, address, bool) {
return abi.decode(_data, (uint256, address, bool));
}
function decodeArray(bytes memory _data) public pure returns (uint256[] memory) {
return abi.decode(_data, (uint256[]));
}
}
六、类型推断 #
6.1 字面量推断 #
solidity
contract TypeInference {
function demo() public pure {
// 整数字面量推断为最小类型
uint8 a = 10; // uint8
uint16 b = 1000; // uint16
uint256 c = 1000000; // uint256
// 地址字面量
address addr = 0x123...; // address
// 字符串字面量
string memory s = "Hello"; // string memory
// 字节字面量
bytes32 hash = hex"1234..."; // bytes32
}
}
6.2 表达式推断 #
solidity
contract ExpressionInference {
function demo() public pure {
uint8 a = 10;
uint8 b = 20;
// 表达式结果类型
uint8 c = a + b; // 可能溢出!
// 安全做法
uint256 d = uint256(a) + uint256(b);
}
}
七、转换注意事项 #
7.1 整数溢出 #
solidity
contract OverflowExample {
function unsafeAdd(uint8 a, uint8 b) public pure returns (uint8) {
return a + b; // 可能溢出
}
function safeAdd(uint8 a, uint8 b) public pure returns (uint256) {
return uint256(a) + uint256(b); // 安全
}
}
7.2 精度丢失 #
solidity
contract PrecisionLoss {
function divide(uint256 a, uint256 b) public pure returns (uint256) {
return a / b; // 整数除法,丢失小数部分
}
function multiplyThenDivide(uint256 a, uint256 b, uint256 c) public pure returns (uint256) {
// 先乘后除,减少精度丢失
return (a * b) / c;
}
}
7.3 地址转换安全 #
solidity
contract SafeAddressConversion {
function safeUintToAddress(uint256 _value) public pure returns (address) {
// 确保值在有效范围内
require(_value <= type(uint160).max, "Value too large");
return address(uint160(_value));
}
}
八、最佳实践 #
8.1 使用显式转换 #
solidity
// 推荐:显式转换
uint256 a = 100;
uint8 b = uint8(a);
// 不推荐:隐式转换(可能不清晰)
uint8 c = 10;
uint256 d = c; // 虽然安全,但不够明确
8.2 避免不必要的转换 #
solidity
// 不推荐
uint256 a = 100;
uint8 b = uint8(a); // 如果a可能大于255,会截断
// 推荐:使用合适的类型
uint256 a = 100; // 直接使用uint256
8.3 使用库函数 #
solidity
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Address.sol";
contract UsingLibraries {
using Strings for uint256;
using Address for address;
function uintToStr(uint256 _value) public pure returns (string memory) {
return _value.toString();
}
function isContract(address _addr) public view returns (bool) {
return _addr.isContract();
}
}
九、总结 #
类型转换要点:
| 转换类型 | 方式 | 安全性 |
|---|---|---|
| 小整数到大整数 | 隐式 | 安全 |
| 大整数到小整数 | 显式 | 可能截断 |
| 有符号到无符号 | 显式 | 可能溢出 |
| 地址与整数 | 显式 | 需检查范围 |
| string与bytes | 显式 | 安全 |
转换规则:
- 隐式转换:小类型到大类型
- 显式转换:大类型到小类型
- 注意整数溢出和精度丢失
- 使用库函数简化转换
接下来,让我们学习特殊类型!
最后更新:2026-03-27