010-Solidity 值类型综合详解

Solidity 值类型综合详解

本文详细讲解 Solidity 中的各种值类型,包含完整定义、特性、边界、常见操作及最佳实践,并提供丰富的实例代码。

目录

  1. 布尔型 (Boolean)
  2. 整型 (Integers)
  3. 定点数 (Fixed Point Numbers)
  4. 地址类型 (Address)
  5. 定长字节数组 (Fixed-size Byte Arrays)
  6. 枚举类型 (Enumerations)
  7. 函数类型 (Function Types)
  8. 值类型之间的类型转换
  9. 常量和不可变量
  10. 值类型的存储与内存操作
  11. 最佳实践与陷阱

1. 布尔型 (Boolean)

定义与特性

  • 关键字:bool
  • 可能的值:truefalse
  • 默认值:false
  • 占用 1 个字节,但在 EVM 中作为 32 字节的字被处理

布尔操作符

  • !(逻辑非)
  • &&(逻辑与)
  • ||(逻辑或)
  • ==(等于)
  • !=(不等于)

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract BooleanExample {
    bool public isActive;
    bool public isFinished = true;
    
    function logicalOperations(bool _a, bool _b) public pure returns (bool, bool, bool) {
        bool and = _a && _b;
        bool or = _a || _b;
        bool not = !_a;
        
        return (and, or, not);
    }
    
    function compareValues(bool _a, bool _b) public pure returns (bool, bool) {
        bool isEqual = _a == _b;
        bool isNotEqual = _a != _b;
        
        return (isEqual, isNotEqual);
    }
    
    function shortCircuitEvaluation(bool _a) public pure returns (bool) {
        // 短路求值示例:如果 _a 为 false,第二个条件不会被计算
        bool result = _a && complexOperation();
        return result;
    }
    
    function complexOperation() public pure returns (bool) {
        // 模拟复杂操作
        return true;
    }
    
    function toggle() public {
        isActive = !isActive;
    }
}

布尔型的优化使用

在存储结构体和数组时,多个布尔值可以通过打包来节省 gas:

solidity

// 高效打包多个布尔值
contract EfficientBooleanPacking {
    struct UserFlags {
        bool isActive;
        bool isVerified;
        bool hasSpecialPermission;
        bool isAdmin;
        // Solidity 自动将这些布尔值打包到一个存储槽中
    }
    
    UserFlags public userFlags;
    
    function setFlags(
        bool _isActive,
        bool _isVerified, 
        bool _hasSpecialPermission,
        bool _isAdmin
    ) public {
        userFlags.isActive = _isActive;
        userFlags.isVerified = _isVerified;
        userFlags.hasSpecialPermission = _hasSpecialPermission;
        userFlags.isAdmin = _isAdmin;
    }
}

2. 整型 (Integers)

定义与特性

Solidity 提供有符号和无符号整数,从 8 位到 256 位不等。

  • 无符号整数:uint8, uint16, uint24, ..., uint256 (或简写 uint)
  • 有符号整数:int8, int16, int24, ..., int256 (或简写 int)
  • 默认值:0
  • uintint 分别是 uint256int256 的别名

整数范围

  • uint8: 0 到 2^8-1 (0 到 255)
  • uint16: 0 到 2^16-1 (0 到 65,535)
  • uint256: 0 到 2^256-1 (约 1.16 * 10^77)
  • int8: -2^7 到 2^7-1 (-128 到 127)
  • int16: -2^15 到 2^15-1 (-32,768 到 32,767)
  • int256: -2^255 到 2^255-1 (约 -5.8 * 10^76 到 5.8 * 10^76)

算术操作符

  • 加法:+
  • 减法:-
  • 乘法:*
  • 除法:/
  • 取模:%
  • 幂运算:**

位运算符

  • 位与:&
  • 位或:|
  • 位异或:^
  • 位非:~
  • 左移:<<
  • 右移:>>

比较运算符

  • 大于:>
  • 小于:<
  • 大于等于:>=
  • 小于等于:<=
  • 等于:==
  • 不等于:!=

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract IntegerExample {
    // 整数声明
    uint8 public smallNumber;
    uint public regularNumber = 123;
    int public signedNumber = -456;
    uint256 public largeNumber = 2**200; // 大约等于 1.6 * 10^60
    
    // 数学运算
    function performArithmetic(uint _a, uint _b) public pure returns (
        uint addition,
        uint subtraction,
        uint multiplication,
        uint division,
        uint modulo,
        uint exponentiation
    ) {
        addition = _a + _b;
        subtraction = _a - _b; // 如果 _b > _a,将在 0.8.0+ 版本中回滚
        multiplication = _a * _b;
        division = _a / _b; // 注意:整数除法会截断(向下取整),_b 不能为 0
        modulo = _a % _b;   // _b 不能为 0
        exponentiation = _a ** 3; // 幂运算,小心溢出
        
        return (addition, subtraction, multiplication, division, modulo, exponentiation);
    }
    
    // 位运算
    function performBitwise(uint8 _a, uint8 _b) public pure returns (
        uint8 bitwiseAnd,
        uint8 bitwiseOr,
        uint8 bitwiseXor,
        uint8 bitwiseNot,
        uint8 leftShift,
        uint8 rightShift
    ) {
        bitwiseAnd = _a & _b;
        bitwiseOr = _a | _b;
        bitwiseXor = _a ^ _b;
        bitwiseNot = ~_a;
        leftShift = _a << 2;  // 左移 2 位,相当于乘以 4
        rightShift = _a >> 2; // 右移 2 位,相当于除以 4
        
        return (bitwiseAnd, bitwiseOr, bitwiseXor, bitwiseNot, leftShift, rightShift);
    }
    
    // 递增和递减
    function incrementDecrement(uint _value) public pure returns (uint, uint) {
        uint incremented = _value + 1;
        uint decremented = _value - 1; // 如果 _value 为 0,将在 0.8.0+ 版本中回滚
        
        return (incremented, decremented);
    }
    
    // 下溢和上溢检查(Solidity 0.8.0+ 会自动检查)
    function overflowExample() public pure returns (uint8) {
        uint8 max = 255;
        // 在 0.8.0 之前,这会导致无声的溢出,结果为 0
        // 在 0.8.0+ 中,这会导致交易回滚
        return max + 1;
    }
    
    function underflowExample() public pure returns (uint8) {
        uint8 min = 0;
        // 在 0.8.0 之前,这会导致无声的下溢,结果为 255
        // 在 0.8.0+ 中,这会导致交易回滚
        return min - 1;
    }
    
    // 使用 unchecked 绕过溢出/下溢检查(仅 0.8.0+)
    function uncheckedExample() public pure returns (uint8) {
        uint8 max = 255;
        unchecked {
            return max + 1; // 这会导致溢出,结果为 0,但不会回滚
        }
    }
    
    // 常见的整数使用模式
    function calculateAverage(uint[] memory values) public pure returns (uint) {
        uint sum = 0;
        
        for (uint i = 0; i < values.length; i++) {
            sum += values[i];
        }
        
        // 在 Solidity 中,整数除法会向下取整
        return values.length > 0 ? sum / values.length : 0;
    }
}

整数边界情况处理

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract IntegerEdgeCases {
    // 安全地处理整数除法(防止除以零错误)
    function safeDivision(uint _a, uint _b) public pure returns (uint, bool) {
        if (_b == 0) {
            return (0, false);
        }
        return (_a / _b, true);
    }
    
    // 检查加法是否会溢出(手动检查,适用于 0.8.0 之前的版本)
    function safeAdd(uint256 _a, uint256 _b) public pure returns (uint256, bool) {
        uint256 result = _a + _b;
        bool overflowed = result < _a; // 如果结果小于其中一个操作数,说明发生了溢出
        return (result, !overflowed);
    }
    
    // 检测最大最小值
    function checkBoundaries() public pure returns (uint, uint, int, int) {
        uint maxUint = type(uint).max;     // 2^256 - 1
        uint minUint = type(uint).min;     // 0
        int maxInt = type(int).max;        // 2^255 - 1
        int minInt = type(int).min;        // -2^255
        
        return (maxUint, minUint, maxInt, minInt);
    }
    
    // 检测特定位宽的最大最小值
    function checkSpecificSizes() public pure returns (uint8, int16, uint32) {
        uint8 maxUint8 = type(uint8).max;   // 255
        int16 minInt16 = type(int16).min;   // -32,768
        uint32 maxUint32 = type(uint32).max; // 4,294,967,295
        
        return (maxUint8, minInt16, maxUint32);
    }
    
    // 整数舍入
    function roundUp(uint _a, uint _b) public pure returns (uint) {
        require(_b > 0, "Divisor cannot be zero");
        // 向上取整除法: (a + b - 1) / b
        return (_a + _b - 1) / _b;
    }
    
    // 计算百分比
    function calculatePercentage(uint _value, uint _percentage) public pure returns (uint) {
        require(_percentage <= 100, "Percentage must be <= 100");
        // 避免小数点后的精度损失,先乘以再除以
        return (_value * _percentage) / 100;
    }
    
    // 在合约中存储和使用大整数
    uint public immutable MAX_SUPPLY = 21_000_000 * 10**18; // 2100万,带有18位小数(常用于代币)
    
    // 整数排序和过滤的例子
    function findMax(uint[] memory values) public pure returns (uint) {
        require(values.length > 0, "Array must not be empty");
        
        uint max = values[0];
        for (uint i = 1; i < values.length; i++) {
            if (values[i] > max) {
                max = values[i];
            }
        }
        
        return max;
    }
}

3. 定点数 (Fixed Point Numbers)

定义与特性

Solidity 中的定点数类型目前还未完全实现,虽然保留了关键字,但无法在当前版本使用。开发者通常使用整数来模拟定点数。

  • 未实现的定点数类型格式:fixed / ufixed
  • 使用整数模拟:通常用 uint 乘以 10^n 来表示带小数点的数值

模拟定点数

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract FixedPointExample {
    // 使用整数来模拟定点数
    // 例如,用 uint256 表示带 18 位小数的数字
    uint256 constant DECIMALS = 18;
    uint256 constant DECIMAL_FACTOR = 10**DECIMALS; // 10^18
    
    // 存储 5.25 (实际存储为 5.25 * 10^18 = 5,250,000,000,000,000,000)
    uint256 public fixedPointValue = 5.25 * DECIMAL_FACTOR;
    
    // 定点数加法
    function add(uint256 _a, uint256 _b) public pure returns (uint256) {
        return _a + _b;
    }
    
    // 定点数减法
    function subtract(uint256 _a, uint256 _b) public pure returns (uint256) {
        require(_a >= _b, "Result would be negative");
        return _a - _b;
    }
    
    // 定点数乘法(需要注意溢出)
    function multiply(uint256 _a, uint256 _b) public pure returns (uint256) {
        // 先执行乘法,然后除以 10^18 以保持小数精度
        return (_a * _b) / DECIMAL_FACTOR;
    }
    
    // 定点数除法
    function divide(uint256 _a, uint256 _b) public pure returns (uint256) {
        require(_b > 0, "Division by zero");
        // 先乘以 10^18 以保持小数精度,然后执行除法
        return (_a * DECIMAL_FACTOR) / _b;
    }
    
    // 示例:计算 50% 的值
    function calculatePercentage(uint256 _value, uint256 _percentage) public pure returns (uint256) {
        // _percentage 应该是一个带 18 位小数的数字
        // 例如,50% 应表示为 0.5 * 10^18 = 500,000,000,000,000,000
        return multiply(_value, _percentage);
    }
    
    // 将 2 位小数的数字转换为内部表示
    function convertFromHuman(uint256 _value) public pure returns (uint256) {
        // 例如,输入 525 表示 5.25
        return _value * DECIMAL_FACTOR / 100;
    }
    
    // 将内部表示转换为 2 位小数的人类可读形式
    function convertToHuman(uint256 _value) public pure returns (uint256) {
        // 例如,输出 525 表示 5.25
        return (_value * 100) / DECIMAL_FACTOR;
    }
}

使用库处理定点数

可以使用第三方库如 PRBMath 或 OpenZeppelin 的 SafeMath 来处理定点数计算:

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// 简单的定点数数学库
library FixedPointMath {
    uint256 constant DECIMALS = 18;
    uint256 constant DECIMAL_FACTOR = 10**DECIMALS; // 10^18
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }
    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }
    
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return (a * b) / DECIMAL_FACTOR;
    }
    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "Division by zero");
        return (a * DECIMAL_FACTOR) / b;
    }
    
    // 将十进制数转换为固定点表示
    // 例如,fromDecimals(5, 2) 将 5.00 转换为固定点表示
    function fromDecimals(uint256 value, uint8 decimals) internal pure returns (uint256) {
        require(decimals <= DECIMALS, "Too many decimals");
        uint256 adjuster = 10**(DECIMALS - decimals);
        return value * adjuster;
    }
    
    // 将固定点表示转换为具有特定小数位数的数字
    // 例如,toDecimals(5 * DECIMAL_FACTOR, 2) 将固定点表示转换为 500(表示 5.00)
    function toDecimals(uint256 value, uint8 decimals) internal pure returns (uint256) {
        require(decimals <= DECIMALS, "Too many decimals");
        uint256 adjuster = 10**(DECIMALS - decimals);
        return value / adjuster;
    }
}

contract FixedPointLibraryExample {
    using FixedPointMath for uint256;
    
    // 以 18 位小数表示的数量
    uint256 public price = 5 * 10**18; // 5.0
    uint256 public quantity = 2 * 10**18; // 2.0
    
    function calculateTotal() public view returns (uint256) {
        // 计算 price * quantity
        return price.mul(quantity);
    }
    
    function calculateShare(uint256 total, uint256 percentage) public pure returns (uint256) {
        // percentage 以 18 位小数表示,例如 50% = 0.5 * 10^18
        uint256 sharePercentage = FixedPointMath.fromDecimals(percentage, 2);
        return total.mul(sharePercentage);
    }
    
    function convertToReadablePrice(uint256 _price) public pure returns (uint256) {
        // 将价格从内部表示(18 位小数)转换为 2 位小数的可读形式
        return FixedPointMath.toDecimals(_price, 2);
    }
}

4. 地址类型 (Address)

定义与特性

Solidity 提供地址类型用于存储以太坊地址。地址类型有两种变体:

  • address:20 字节的以太坊地址
  • address payable:与 address 相同,但有额外的 transfersend 成员函数

地址成员

  • balance: 查询地址的余额(以 wei 为单位)
  • code: 获取地址存储的代码
  • codehash: 获取地址代码的哈希值
  • transfer(): 向地址发送 ETH(会自动转发 2300 gas,失败时会回滚)
  • send(): 向地址发送 ETH(会自动转发 2300 gas,失败时返回 false)
  • call(): 低级函数调用,返回是否成功以及任何返回数据
  • delegatecall(): 低级函数调用,使用调用合约的存储、当前地址和余额
  • staticcall(): 低级函数调用,不允许状态修改

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract AddressExample {
    // 地址声明
    address public owner;
    address payable public treasury;
    
    constructor() {
        owner = msg.sender;
        treasury = payable(msg.sender); // 将普通地址转换为 address payable
    }
    
    // 检查地址是否为合约
    function isContract(address _addr) public view returns (bool) {
        uint256 codeSize;
        assembly {
            codeSize := extcodesize(_addr)
        }
        return codeSize > 0;
    }
    
    // 地址余额查询
    function getBalance(address _addr) public view returns (uint256) {
        return _addr.balance;
    }
    
    // 比较地址
    function compareAddresses(address _addr1, address _addr2) public pure returns (bool) {
        return _addr1 == _addr2;
    }
    
    // 使用 transfer 发送 ETH(接收者有 2300 gas 限制)
    function sendEtherWithTransfer(address payable _to, uint256 _amount) public {
        // 会自动转发 2300 gas,失败时会回滚
        _to.transfer(_amount);
    }
    
    // 使用 send 发送 ETH(接收者有 2300 gas 限制)
    function sendEtherWithSend(address payable _to, uint256 _amount) public returns (bool) {
        // 会自动转发 2300 gas,失败时返回 false
        return _to.send(_amount);
    }
    
    // 使用 call 发送 ETH(灵活的 gas 限制)
    function sendEtherWithCall(address payable _to, uint256 _amount) public returns (bool) {
        // 可以传递自定义 gas 值,推荐使用的方式
        (bool success, ) = _to.call{value: _amount}("");
        return success;
    }
    
    // 调用其他合约的函数
    function callExternalFunction(address _contract, bytes memory _data) public returns (bool, bytes memory) {
        // 调用其他合约的函数(低级调用)
        (bool success, bytes memory returnData) = _contract.call(_data);
        return (success, returnData);
    }
    
    // 使用 staticcall 进行只读调用
    function staticCallExternalFunction(address _contract, bytes memory _data) public view returns (bool, bytes memory) {
        // 调用其他合约的函数(只读调用)
        (bool success, bytes memory returnData) = _contract.staticcall(_data);
        return (success, returnData);
    }
    
    // 使用 delegatecall 调用其他合约的函数(保留 msg.sender 和当前合约上下文)
    function delegateCallFunction(address _contract, bytes memory _data) public returns (bool, bytes memory) {
        // 使用其他合约的代码,但使用当前合约的存储
        (bool success, bytes memory returnData) = _contract.delegatecall(_data);
        return (success, returnData);
    }
    
    // 接收 ETH
    receive() external payable {}
    
    // 从合约中提取 ETH
    function withdrawEther(uint256 _amount) public {
        require(msg.sender == owner, "Only owner can withdraw");
        treasury.transfer(_amount);
    }
    
    // 将普通地址转换为 address payable
    function convertToPayable(address _addr) public pure returns (address payable) {
        return payable(_addr);
    }
    
    // 将合约地址转换为接口类型(Type Casting)
    function castToInterface(address _contractAddress) public view returns (bool) {
        // 假设 _contractAddress 实现了 IERC20 接口
        IERC20 token = IERC20(_contractAddress);
        
        // 调用接口方法
        uint256 totalSupply = token.totalSupply();
        return totalSupply > 0;
    }
}

// ERC20 接口定义(用于上面的例子)
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}

安全使用地址的最佳实践

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract AddressSafetyExample {
    address public immutable owner;
    
    constructor() {
        owner = msg.sender;
    }
    
    // 零地址检查
    function setRecipient(address _recipient) public pure returns (address) {
        require(_recipient != address(0), "Cannot use zero address");
        return _recipient;
    }
    
    // 安全转账模式
    function safeTransferETH(address payable _to, uint256 _amount) public returns (bool) {
        require(_to != address(0), "Cannot transfer to zero address");
        require(address(this).balance >= _amount, "Insufficient balance");
        
        (bool success, ) = _to.call{value: _amount}("");
        require(success, "ETH transfer failed");
        
        return true;
    }
    
    // 检查钱包地址格式
    function isValidAddress(address _addr) public pure returns (bool) {
        // 地址不能为零,且长度必须为 20 字节(160 位)
        // Solidity 类型系统已经确保了长度为 20 字节,所以我们只需检查非零
        return _addr != address(0);
    }
    
    // 检查 EOA vs 合约地址
    function isExternallyOwnedAccount(address _addr) public view returns (bool) {
        uint256 codeSize;
        assembly {
            codeSize := extcodesize(_addr)
        }
        // EOA 的代码大小应该为 0
        return codeSize == 0;
    }
    
    // 安全调用合约
    function safeContractCall(address _contract, bytes memory _data) public returns (bool, bytes memory) {
        require(_contract != address(0), "Invalid contract address");
        require(isContract(_contract), "Target is not a contract");
        
        (bool success, bytes memory returnData) = _contract.call(_data);
        
        if (!success) {
            // 如果调用失败并返回错误信息(错误信息通常是以 revert 原因字符串格式编码的)
            if (returnData.length > 0) {
                // 提取错误信息并重新抛出
                assembly {
                    let returnDataSize := mload(returnData)
                    revert(add(32, returnData), returnDataSize)
                }
            } else {
                revert("Contract call failed without error");
            }
        }
        
        return (success, returnData);
    }
    
    // 辅助函数:检查地址是否为合约
    function isContract(address _addr) public view returns (bool) {
        uint256 codeSize;
        assembly {
            codeSize := extcodesize(_addr)
        }
        return codeSize > 0;
    }
    
    // 防止可重入攻击的 ETH 发送
    bool private locked;
    
    modifier nonReentrant() {
        require(!locked, "Reentrant call");
        locked = true;
        _;
        locked = false;
    }
    
    function sendEtherSafely(address payable _recipient, uint256 _amount) public nonReentrant {
        require(_recipient != address(0), "Invalid recipient");
        
        (bool success, ) = _recipient.call{value: _amount}("");
        require(success, "ETH transfer failed");
    }
    
    // 接收 ETH
    receive() external payable {}
}

5. 定长字节数组 (Fixed-size Byte Arrays)

定义与特性

Solidity 提供两种处理字节数据的类型:

  • 固定大小的字节数组:bytes1, bytes2, bytes3, ..., bytes32
  • 可变大小的字节数组:bytesstring(这些是引用类型,不是值类型)

本节关注固定大小的字节数组(值类型)。

操作与方法

  • 比较运算符:==, !=
  • 位运算符:&, |, ^, ~, <<, >>
  • 索引访问(只读):bytesN[k] 返回第 k 个字节(0 索引)

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract FixedBytesExample {
    // 固定大小字节数组声明
    bytes1 public singleByte = 0xa1;          // 1 字节,存储 0xa1
    bytes2 public twoBytes = 0xa1b2;          // 2 字节,存储 0xa1b2
    bytes16 public sixteenBytes = 0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6; // 16 字节
    bytes32 public hash = keccak256("Hello"); // 32 字节,存储哈希值
    
    // 将地址转换为 bytes20
    function addressToBytes20(address _addr) public pure returns (bytes20) {
        return bytes20(_addr);
    }
    
    // 将 bytes32 转换为地址
    function bytes32ToAddress(bytes32 _bytes) public pure returns (address) {
        return address(uint160(uint256(_bytes)));
    }
    
    // 比较两个 bytes32 值
    function compareBytes(bytes32 _a, bytes32 _b) public pure returns (bool) {
        return _a == _b;
    }
    
    // 位运算示例
    function bitwiseOperations(bytes2 _a, bytes2 _b) public pure returns (
        bytes2 bitwiseAnd,
        bytes2 bitwiseOr,
        bytes2 bitwiseXor,
        bytes2 bitwiseNot,
        bytes2 leftShift,
        bytes2 rightShift
    ) {
        bitwiseAnd = _a & _b;
        bitwiseOr = _a | _b;
        bitwiseXor = _a ^ _b;
        bitwiseNot = ~_a;
        leftShift = _a << 4;   // 左移 4 位
        rightShift = _a >> 4;  // 右移 4 位
        
        return (bitwiseAnd, bitwiseOr, bitwiseXor, bitwiseNot, leftShift, rightShift);
    }
    
    // 访问 bytes32 中的单个字节
    function getByteAt(bytes32 _value, uint8 _index) public pure returns (bytes1) {
        require(_index < 32, "Index out of bounds");
        return _value[_index];
    }
    
    // 将 bytes32 转换为 uint256
    function bytes32ToUint(bytes32 _value) public pure returns (uint256) {
        return uint256(_value);
    }
    
    // 将字节数组拼接在一起
    function concatenateBytes() public pure returns (bytes memory) {
        bytes1 a = 0xa1;
        bytes1 b = 0xb2;
        bytes1 c = 0xc3;
        
        // 将单个字节拼接到动态字节数组中
        bytes memory result = new bytes(3);
        result[0] = a;
        result[1] = b;
        result[2] = c;
        
        return result;
    }
    
    // 使用字节作为标志或状态标识符
    bytes1 private flags = 0x00;  // 每一位表示一个标志
    
    // 设置标志位
    function setFlag(uint8 _position, bool _value) public {
        require(_position < 8, "Position out of bounds");
        
        if (_value) {
            // 设置指定位为 1
            flags |= bytes1(uint8(1 << _position));
        } else {
            // 设置指定位为 0
            flags &= ~bytes1(uint8(1 << _position));
        }
    }
    
    // 获取标志位
    function getFlag(uint8 _position) public view returns (bool) {
        require(_position < 8, "Position out of bounds");
        return (uint8(flags) & (1 << _position)) != 0;
    }
    
    // 获取当前所有标志
    function getFlags() public view returns (bytes1) {
        return flags;
    }
}

高级字节操作

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract AdvancedBytesExample {
    // 构建字节数组 - 按字节构建 bytes32
    function buildBytes32() public pure returns (bytes32) {
        bytes32 result;
        
        assembly {
            // 存储 "Hello, World!" 字符串到 bytes32
            // 注意:字符串以右对齐方式存储
            result := 0x48656c6c6f2c20576f726c642100000000000000000000000000000000000000
        }
        
        return result;
    }
    
    // 从字节数组提取部分内容
    function extractString(bytes32 _input) public pure returns (string memory) {
        // 找到结束零的位置(如果有)
        uint8 length = 32;
        for (uint8 i = 0; i < 32; i++) {
            if (_input[i] == 0) {
                length = i;
                break;
            }
        }
        
        // 创建字符串并复制非零字节
        bytes memory result = new bytes(length);
        for (uint8 i = 0; i < length; i++) {
            result[i] = _input[i];
        }
        
        return string(result);
    }
    
    // 使用 bytes32 存储最多 32 个字符的字符串
    function stringToBytes32(string memory _input) public pure returns (bytes32) {
        bytes32 result;
        
        assembly {
            // 从内存加载字符串
            result := mload(add(_input, 32))
        }
        
        return result;
    }
    
    // 两个 bytes32 值的位操作合并
    function mergeData(bytes32 _a, bytes32 _b, uint8 _bitsFromA) public pure returns (bytes32) {
        require(_bitsFromA <= 256, "Invalid bit count");
        
        uint256 mask = (1 << _bitsFromA) - 1;
        mask = mask << (256 - _bitsFromA);
        
        uint256 aVal = uint256(_a) & mask;
        uint256 bVal = uint256(_b) & ~mask;
        
        return bytes32(aVal | bVal);
    }
    
    // 将数字压缩到单个 bytes32 中
    // 例如,存储 4 个 uint64 值到一个 bytes32 中
    function packUints(uint64 a, uint64 b, uint64 c, uint64 d) public pure returns (bytes32) {
        return bytes32(
            (uint256(a) << 192) |
            (uint256(b) << 128) |
            (uint256(c) << 64) |
            uint256(d)
        );
    }
    
    // 从 bytes32 解包 uint64 值
    function unpackUint64(bytes32 packed, uint8 index) public pure returns (uint64) {
        require(index < 4, "Index out of bounds");
        return uint64(uint256(packed) >> (64 * (3 - index)));
    }
    
    // 使用 bytes32 作为映射键
    mapping(bytes32 => uint256) private dataStore;
    
    // 存储数据
    function storeData(bytes32 key, uint256 value) public {
        dataStore[key] = value;
    }
    
    // 检索数据
    function getData(bytes32 key) public view returns (uint256) {
        return dataStore[key];
    }
    
    // 从 String 创建哈希作为唯一标识符
    function getKeyFromString(string memory input) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(input));
    }
}

6. 枚举类型 (Enumerations)

定义与特性

枚举类型用于创建用户定义类型,包含一组命名常量。

  • 枚举是值类型,在内部表示为整数(从 0 开始)
  • 可以显式设置枚举常量的值
  • 默认值是第一个定义的枚举常量(索引为 0)

操作和限制

  • 可以将枚举类型转换为整数,反之亦然
  • 无法在运行时动态添加枚举值

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract EnumExample {
    // 定义一个状态枚举
    enum Status {
        Pending,    // 0
        Active,     // 1
        Inactive,   // 2
        Cancelled   // 3
    }
    
    // 状态变量
    Status public currentStatus;
    
    // 另一个示例:支付方式
    enum PaymentMethod {
        CreditCard, // 0
        BankTransfer, // 1
        Crypto      // 2
    }
    
    // 带有自定义值的枚举(通过类型转换处理)
    enum Priority {
        Low,      // 0
        Medium,   // 1
        High,     // 2
        Critical  // 3
    }
    
    // 映射不同状态到权重
    mapping(Status => uint256) public statusWeights;
    
    // 构造函数
    constructor() {
        currentStatus = Status.Pending; // 设置初始状态
        
        // 初始化状态权重
        statusWeights[Status.Pending] = 1;
        statusWeights[Status.Active] = 2;
        statusWeights[Status.Inactive] = 1;
        statusWeights[Status.Cancelled] = 0;
    }
    
    // 设置状态
    function setStatus(Status _newStatus) public {
        currentStatus = _newStatus;
    }
    
    // 获取当前状态
    function getStatus() public view returns (Status) {
        return currentStatus;
    }
    
    // 获取状态名称
    function getStatusName() public view returns (string memory) {
        if (currentStatus == Status.Pending) return "Pending";
        if (currentStatus == Status.Active) return "Active";
        if (currentStatus == Status.Inactive) return "Inactive";
        if (currentStatus == Status.Cancelled) return "Cancelled";
        return "Unknown";
    }
    
    // 枚举转换为 uint
    function getStatusAsUint() public view returns (uint) {
        return uint(currentStatus);
    }
    
    // uint 转换为枚举
    function setStatusFromUint(uint _status) public {
        require(_status <= uint(type(Status).max), "Invalid status");
        currentStatus = Status(_status);
    }
    
    // 比较枚举值
    function isActive() public view returns (bool) {
        return currentStatus == Status.Active;
    }
    
    // 使用枚举作为参数
    function processPayment(PaymentMethod _method, uint256 _amount) public pure returns (string memory) {
        if (_method == PaymentMethod.CreditCard) {
            return string(abi.encodePacked("Processing credit card payment of ", _uintToString(_amount)));
        } else if (_method == PaymentMethod.BankTransfer) {
            return string(abi.encodePacked("Processing bank transfer of ", _uintToString(_amount)));
        } else if (_method == PaymentMethod.Crypto) {
            return string(abi.encodePacked("Processing crypto payment of ", _uintToString(_amount)));
        } else {
            return "Unknown payment method";
        }
    }
    
    // 遍历所有可能的枚举值
    function getAllStatusWeights() public view returns (uint256[] memory) {
        uint256 count = uint(type(Status).max) + 1;
        uint256[] memory weights = new uint256[](count);
        
        for (uint i = 0; i < count; i++) {
            weights[i] = statusWeights[Status(i)];
        }
        
        return weights;
    }
    
    // 获取枚举成员数量
    function getStatusCount() public pure returns (uint256) {
        return uint(type(Status).max) + 1;
    }
    
    // 辅助函数:将 uint 转换为字符串(简化版)
    function _uintToString(uint256 value) private pure returns (string memory) {
        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);
    }
}

枚举的高级使用案例

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract AdvancedEnumExample {
    // 表示状态机的枚举
    enum OrderState {
        Created,
        Paid,
        Shipped,
        Delivered,
        Cancelled,
        Refunded
    }
    
    // 投票选择的枚举
    enum Vote {
        Abstain, // 0
        Yes,     // 1
        No       // 2
    }
    
    // 订单结构体
    struct Order {
        OrderState state;
        uint256 amount;
        address customer;
        uint256 timestamp;
    }
    
    // 状态转换规则
    mapping(OrderState => OrderState[]) private allowedTransitions;
    
    // 订单存储
    mapping(uint256 => Order) public orders;
    uint256 public orderCount;
    
    // 用户投票记录
    mapping(address => mapping(uint256 => Vote)) public userVotes;
    
    constructor() {
        // 初始化状态转换规则
        allowedTransitions[OrderState.Created] = [OrderState.Paid, OrderState.Cancelled];
        allowedTransitions[OrderState.Paid] = [OrderState.Shipped, OrderState.Cancelled];
        allowedTransitions[OrderState.Shipped] = [OrderState.Delivered, OrderState.Cancelled];
        allowedTransitions[OrderState.Delivered] = [OrderState.Refunded];
        allowedTransitions[OrderState.Cancelled] = [OrderState.Refunded];
        // Refunded 是终态,没有可能的转换
    }
    
    // 创建订单
    function createOrder(uint256 _amount) public returns (uint256) {
        uint256 orderId = orderCount++;
        
        orders[orderId] = Order({
            state: OrderState.Created,
            amount: _amount,
            customer: msg.sender,
            timestamp: block.timestamp
        });
        
        return orderId;
    }
    
    // 更新订单状态
    function updateOrderState(uint256 _orderId, OrderState _newState) public {
        Order storage order = orders[_orderId];
        require(order.customer != address(0), "Order does not exist");
        
        // 检查状态转换是否有效
        bool validTransition = false;
        OrderState[] memory allowed = allowedTransitions[order.state];
        
        for (uint i = 0; i < allowed.length; i++) {
            if (allowed[i] == _newState) {
                validTransition = true;
                break;
            }
        }
        
        require(validTransition, "Invalid state transition");
        
        // 更新状态
        order.state = _newState;
        order.timestamp = block.timestamp;
    }
    
    // 检查订单是否已完成
    function isOrderComplete(uint256 _orderId) public view returns (bool) {
        OrderState state = orders[_orderId].state;
        return state == OrderState.Delivered || state == OrderState.Refunded;
    }
    
    // 使用枚举进行投票
    function vote(uint256 _proposalId, Vote _vote) public {
        require(_vote == Vote.Abstain || _vote == Vote.Yes || _vote == Vote.No, "Invalid vote");
        userVotes[msg.sender][_proposalId] = _vote;
    }
    
    // 统计投票数
    function countVotes(uint256 _proposalId, address[] memory _voters) public view returns (
        uint256 abstainCount,
        uint256 yesCount,
        uint256 noCount
    ) {
        for (uint256 i = 0; i < _voters.length; i++) {
            Vote userVote = userVotes[_voters[i]][_proposalId];
            
            if (userVote == Vote.Abstain) {
                abstainCount++;
            } else if (userVote == Vote.Yes) {
                yesCount++;
            } else if (userVote == Vote.No) {
                noCount++;
            }
        }
        
        return (abstainCount, yesCount, noCount);
    }
    
    // 将枚举转换为字符串
    function getOrderStateString(uint256 _orderId) public view returns (string memory) {
        OrderState state = orders[_orderId].state;
        
        if (state == OrderState.Created) return "Created";
        if (state == OrderState.Paid) return "Paid";
        if (state == OrderState.Shipped) return "Shipped";
        if (state == OrderState.Delivered) return "Delivered";
        if (state == OrderState.Cancelled) return "Cancelled";
        if (state == OrderState.Refunded) return "Refunded";
        
        return "Unknown";
    }
}

7. 函数类型 (Function Types)

定义与特性

Solidity 中的函数类型表示对函数的引用。函数类型是值类型,但与数组和结构体一样,作为参数传递时存储位置很重要。

  • 语法:function (<parameter types>) {internal|external} [pure|view|payable] [returns (<return types>)]
  • 可以是内部 (internal) 或外部 (external) 类型
  • 函数可以有 pureviewpayable 修饰符
  • 函数类型变量初始值为 null

函数类型的使用

  • 可以将函数分配给变量
  • 可以将函数作为参数传递
  • 可以从函数返回函数
  • 可以调用存储在变量中的函数

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract FunctionTypeExample {
    // 定义一个内部函数类型的变量
    function(uint256, uint256) internal pure returns (uint256) mathOperation;
    
    // 声明一个事件,跟踪操作
    event OperationPerformed(string operationName, uint256 a, uint256 b, uint256 result);
    
    // 初始化函数类型变量
    constructor() {
        mathOperation = add; // 默认为加法
    }
    
    // 加法函数
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }
    
    // 减法函数
    function subtract(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a - b : 0;
    }
    
    // 乘法函数
    function multiply(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }
    
    // 除法函数
    function divide(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "Cannot divide by zero");
        return a / b;
    }
    
    // 设置当前操作为加法
    function setOperationToAdd() public {
        mathOperation = add;
    }
    
    // 设置当前操作为减法
    function setOperationToSubtract() public {
        mathOperation = subtract;
    }
    
    // 设置当前操作为乘法
    function setOperationToMultiply() public {
        mathOperation = multiply;
    }
    
    // 设置当前操作为除法
    function setOperationToDivide() public {
        mathOperation = divide;
    }
    
    // 执行当前设置的操作
    function execute(uint256 a, uint256 b) public returns (uint256) {
        uint256 result = mathOperation(a, b);
        
        string memory operationName;
        if (mathOperation == add) operationName = "Addition";
        else if (mathOperation == subtract) operationName = "Subtraction";
        else if (mathOperation == multiply) operationName = "Multiplication";
        else if (mathOperation == divide) operationName = "Division";
        else operationName = "Unknown";
        
        emit OperationPerformed(operationName, a, b, result);
        
        return result;
    }
    
    // 将函数作为参数传递
    function computeWithFunction(
        uint256 a,
        uint256 b,
        function(uint256, uint256) internal pure returns (uint256) operation
    ) public pure returns (uint256) {
        return operation(a, b);
    }
    
    // 返回函数
    function getOperation(string memory opName) public pure returns (
        function(uint256, uint256) internal pure returns (uint256)
    ) {
        bytes32 opHash = keccak256(abi.encodePacked(opName));
        
        if (opHash == keccak256(abi.encodePacked("add"))) return add;
        if (opHash == keccak256(abi.encodePacked("subtract"))) return subtract;
        if (opHash == keccak256(abi.encodePacked("multiply"))) return multiply;
        if (opHash == keccak256(abi.encodePacked("divide"))) return divide;
        
        revert("Unknown operation");
    }
    
    // 使用外部函数类型
    function getAddFunction() public view returns (function(uint256, uint256) external pure returns (uint256)) {
        return this.addExternal;
    }
    
    // 外部加法函数
    function addExternal(uint256 a, uint256 b) external pure returns (uint256) {
        return a + b;
    }
    
    // 使用外部函数类型调用
    function callExternalFunction(
        function(uint256, uint256) external pure returns (uint256) externalFunc,
        uint256 a,
        uint256 b
    ) public pure returns (uint256) {
        return externalFunc(a, b);
    }
    
    // 函数选择器示例
    function getAddSelector() public pure returns (bytes4) {
        return this.addExternal.selector;
    }
}

高级函数类型用例:策略模式与回调

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract AdvancedFunctionTypes {
    // 定义一个函数类型的数组
    function(uint256) internal returns (uint256)[] public processors;
    
    // 回调函数定义
    function(uint256, bool) internal callback;
    
    // 事件
    event Processing(uint256 input, uint256 output);
    event CallbackTriggered(uint256 value, bool success);
    
    // 一些示例处理函数
    function doubleValue(uint256 input) internal pure returns (uint256) {
        return input * 2;
    }
    
    function addTen(uint256 input) internal pure returns (uint256) {
        return input + 10;
    }
    
    function square(uint256 input) internal pure returns (uint256) {
        return input * input;
    }
    
    // 初始化处理器数组
    function initializeProcessors() public {
        // 清除现有处理器
        delete processors;
        
        // 添加处理器函数
        processors.push(doubleValue);
        processors.push(addTen);
        processors.push(square);
    }
    
    // 执行所有处理器
    function processValue(uint256 input) public returns (uint256) {
        uint256 result = input;
        
        for (uint256 i = 0; i < processors.length; i++) {
            result = processors[i](result);
            emit Processing(input, result);
        }
        
        return result;
    }
    
    // 设置回调函数
    function setCallbackToSuccess() public {
        callback = successCallback;
    }
    
    function setCallbackToFailure() public {
        callback = failureCallback;
    }
    
    // 回调函数实现
    function successCallback(uint256 value, bool success) internal {
        emit CallbackTriggered(value, success);
        // 可以在这里添加更多逻辑
    }
    
    function failureCallback(uint256 value, bool success) internal {
        emit CallbackTriggered(value, success);
        // 处理失败情况的逻辑
        revert("Operation failed");
    }
    
    // 执行带回调的异步操作模拟
    function executeWithCallback(uint256 value, bool shouldSucceed) public {
        require(address(callback) != address(0), "Callback not set");
        
        // 执行一些操作,然后调用回调
        uint256 result = value * 2;
        
        // 仅在成功时调用回调
        if (shouldSucceed) {
            callback(result, true);
        } else {
            callback(result, false);
        }
    }
    
    // 使用函数类型实现策略模式
    enum Strategy { Conservative, Moderate, Aggressive }
    
    function(uint256) internal pure returns (uint256) investmentStrategy;
    
    function setStrategy(Strategy _strategy) public {
        if (_strategy == Strategy.Conservative) {
            investmentStrategy = conservativeStrategy;
        } else if (_strategy == Strategy.Moderate) {
            investmentStrategy = moderateStrategy;
        } else if (_strategy == Strategy.Aggressive) {
            investmentStrategy = aggressiveStrategy;
        } else {
            revert("Unknown strategy");
        }
    }
    
    function conservativeStrategy(uint256 amount) internal pure returns (uint256) {
        // 保守策略:返回 5% 收益
        return amount + (amount * 5 / 100);
    }
    
    function moderateStrategy(uint256 amount) internal pure returns (uint256) {
        // 中等策略:返回 10% 收益
        return amount + (amount * 10 / 100);
    }
    
    function aggressiveStrategy(uint256 amount) internal pure returns (uint256) {
        // 激进策略:返回 20% 收益,但有 10% 的亏损风险
        if (amount % 10 == 0) { // 简单的模拟亏损情况
            return amount - (amount * 10 / 100);
        } else {
            return amount + (amount * 20 / 100);
        }
    }
    
    // 执行投资
    function invest(uint256 amount) public view returns (uint256) {
        require(address(investmentStrategy) != address(0), "Strategy not set");
        return investmentStrategy(amount);
    }
}

8. 值类型之间的类型转换

隐式类型转换

Solidity 在满足以下条件时执行隐式类型转换:

  • 类型之间的大小关系明确(如 uint8uint16
  • 类型之间不会出现信息丢失

显式类型转换

对于不能隐式转换的情况,需要使用显式类型转换:

  • 较大类型到较小类型(如 uint256uint8
  • 有符号类型与无符号类型之间(如 int256uint256
  • 地址类型与整数类型之间

实例代码

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract TypeConversionExample {
    // 隐式类型转换
    function implicitConversions() public pure returns (uint256, int256) {
        uint8 smallUint = 100;
        uint256 largeUint = smallUint; // uint8 隐式转换为 uint256
        
        int16 smallInt = 200;
        int256 largeInt = smallInt;    // int16 隐式转换为 int256
        
        return (largeUint, largeInt);
    }
    
    // 显式类型转换
    function explicitConversions() public pure returns (
        uint8,
        int8,
        uint256,
        bytes32,
        address
    ) {
        uint256 largeUint = 100;
        uint8 smallUint = uint8(largeUint); // 显式缩小转换
        
        int256 largeInt = -100;
        int8 smallInt = int8(largeInt);   // 显式缩小转换
        
        int256 signedInt = 0x64;
        uint256 unsignedInt = uint256(signedInt); // 显式转换 int 到 uint
        
        uint256 uintValue = 0xaabbccdd;
        bytes32 bytes32Value = bytes32(uintValue); // uint 到 bytes32
        
        bytes20 bytes20Value = bytes20(0x1234567890123456789012345678901234567890);
        address addressValue = address(bytes20Value); // bytes20 到 address
        
        return (smallUint, smallInt, unsignedInt, bytes32Value, addressValue);
    }
    
    // 数据丢失的风险
    function truncationRisks() public pure returns (uint8, int8) {
        uint256 largeUint = 300; // 超出 uint8 范围 (0-255)
        uint8 truncatedUint = uint8(largeUint); // 结果为 44 (300 - 256 = 44)
        
        int256 largeInt = 130; // 超出 int8 范围 (-128 到 127)
        int8 truncatedInt = int8(largeInt); // 结果为 -126 (130 - 256 = -126)
        
        return (truncatedUint, truncatedInt);
    }
    
    // 从 bytes1, bytes2, etc. 到数字的转换
    function bytesToIntegers() public pure returns (uint8, uint16, uint256) {
        bytes1 b1 = 0xA9;
        uint8 u8 = uint8(b1); // 结果为 169
        
        bytes2 b2 = 0xA9F0;
        uint16 u16 = uint16(b2); // 结果为 43504
        
        bytes32 b32 = bytes32(uint256(0x1234567890));
        uint256 u256 = uint256(b32); // 结果为 0x1234567890
        
        return (u8, u16, u256);
    }
    
    // 布尔转换
    function booleanConversions() public pure returns (uint8, bool, bool) {
        bool trueBool = true;
        uint8 fromTrue = uint8(trueBool); // 1
        
        uint256 nonZero = 123;
        uint256 zero = 0;
        bool fromNonZero = (nonZero != 0); // true
        bool fromZero = (zero != 0);      // false
        
        return (fromTrue, fromNonZero, fromZero);
    }
    
    // 地址与整数/字节之间的转换
    function addressConversions() public pure returns (
        address,
        uint160,
        bytes20
    ) {
        address addr = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
        
        uint160 addrUint = uint160(addr); // 地址转为 uint160
        bytes20 addrBytes = bytes20(addr); // 地址转为 bytes20
        
        return (addr, addrUint, addrBytes);
    }
    
    // 安全类型转换
    function safeTypeConversion(uint256 value) public pure returns (uint8, bool) {
        // 检查值是否在 uint8 范围内
        if (value > type(uint8).max) {
            return (0, false);
        }
        
        return (uint8(value), true);
    }
    
    // 处理有符号和无符号整数之间的转换
    function signedUnsignedConversion(int256 signedValue) public pure returns (uint256, bool) {
        // 检查是否为负数
        if (signedValue < 0) {
            return (0, false);
        }
        
        return (uint256(signedValue), true);
    }
    
    // 类型转换在实际应用中的用例:货币单位转换
    function convertEtherToWei(uint256 etherAmount) public pure returns (uint256) {
        // 1 Ether = 10^18 Wei
        return etherAmount * 1 ether;
    }
    
    function convertWeiToGwei(uint256 weiAmount) public pure returns (uint256) {
        // 1 Gwei = 10^9 Wei
        return weiAmount / 1 gwei;
    }
}

更复杂的类型转换示例

solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract AdvancedTypeConversions {
    // 字节数组和字符串之间的转换
    function bytesToString(bytes memory data) public pure returns (string memory) {
        return string(data);
    }
    
    function stringToBytes(string memory str) public pure returns (bytes memory) {
        return bytes(str);
    }
    
    // 十六进制字符串/数字之间的转换
    function addressToHexString(address addr) public pure returns (string memory) {
        return _toHexString(uint256(uint160(addr)), 20);
    }
    
    function uint256ToHexString(uint256 value) public pure returns (string memory) {
        return _toHexString(value, 32);
    }
    
    // 辅助函数:将 uint256 转换为十六进制字符串
    function _toHexString(uint256 value, uint256 length) internal 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] = _toHexChar(uint8(value & 0xf));
            value >>= 4;
        }
        
        return string(buffer);
    }
    
    // 辅助函数:将 4 位转换为十六进制字符
    function _toHexChar(uint8 value) internal pure returns (bytes1) {
        if (value < 10) {
            return bytes1(uint8(bytes1("0")) + value);
        } else {
            return bytes1(uint8(bytes1("a")) + value - 10);
        }
    }
    
    // 有符号整数和无符号整数之间类型转换的边界情况
    function signedToUnsignedEdgeCases() public pure returns (
        uint256, // 从最大 int256 转换
        uint256, // 从最小 int256 转换(会失败)
        int256,  // 从最大 uint256 转换(会失败)
        int256   // 从 uint256(0) 转换
    ) {
        int256 maxInt256 = type(int256).max;
        int256 minInt256 = type(int256).min;
        uint256 maxUint256 = type(uint256).max;
        uint256 minUint256 = 0;
        
        uint256 maxIntToUint;
        uint256 minIntToUint;
        int256 maxUintToInt;
        int256 minUintToInt;
        
        // 安全转换
        try this.unsafeIntToUint(maxInt256) returns (uint256 result) {
            maxIntToUint = result;
        } catch {
            maxIntToUint = 0; // 转换失败
        }
        
        // 这个会失败(负数不能转换为 uint)
        try this.unsafeIntToUint(minInt256) returns (uint256 result) {
            minIntToUint = result;
        } catch {
            minIntToUint = 0; // 转换失败
        }
        
        // 这个会失败(maxUint256 超出 int256 范围)
        try this.unsafeUintToInt(maxUint256) returns (int256 result) {
            maxUintToInt = result;
        } catch {
            maxUintToInt = 0; // 转换失败
        }
        
        // 安全转换
        try this.unsafeUintToInt(minUint256) returns (int256 result) {
            minUintToInt = result;
        } catch {
            minUintToInt = 0; // 转换失败
        }
        
        return (maxIntToUint, minIntToUint, maxUintToInt, minUintToInt);
    }
    
    // 用于测试转换边界的不安全函数
    function unsafeIntToUint(int256 value) external pure returns (uint256) {
        require(value >= 0, "Negative value cannot be converted to uint");
        return uint256(value);
    }
    
    function unsafeUintToInt(uint256 value) external pure returns (int256) {
        require(value <= uint256(type(int256).max), "Value too large for int256");
        return int256(value);
    }
    
    // 使用位操作符进行类型转换
    function bitOperationConversions() public pure returns (
        uint32,
        uint32,
        bytes4
    ) {
        uint256 fullValue = 0x12345678ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF;
        
        // 提取低 32 位
        uint32 low32Bits = uint32(fullValue);
        
        // 提取高 32 位
        uint32 high32Bits = uint32(fullValue >> 224);
        
        // 创建函数选择器(4 字节)
        bytes4 selector = bytes4(keccak256("transfer(address,uint256)"));
        
        return (low32Bits, high32Bits, selector);
    }
    
    // 安全地将 uint 数组转换为 int 数组
    function uintArrayToIntArray(uint256[] memory uintArray) public pure returns (int256[] memory) {
        int256[] memory intArray = new int256[](uintArray.length);
        
        for (uint256 i = 0; i < uintArray.length; i++) {
            require(uintArray[i] <= uint256(type(int256).max), "Value too large for int256");
            intArray[i] = int256(uintArray[i]);
        }
        
        return intArray;
    }
}

9. 常量和不可变量

定义与特性

Solidity 提供两种声明固定值的方法:

  • constant:在编译时必须确定的值,不占用存储空间
  • immutable:可以在构造函数中分配的值,在部署后不可更改

常量

  • 使用关键字 constant 声明
  • 必须在声明时赋值
  • 可以包含复杂表达式,但仅限于编译时可确定的计算
  • 每次使用都复制其实际值,不占用存储空间

不可变量

  • 使用关键字 immutable 声明
  • 可以在构造函数中分配
  • 部署后不可修改
  • 比存储变量更节省 gas

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值