类型转换 #

一、类型转换概述 #

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