# 值类型

By [startha](https://paragraph.com/@starha) · 2023-08-29

---

Solidity基本数据类型
--------------

1.  **值类型（Value Type）**：包括布尔类型，整形等。
    
2.  **引用类型（Reference Tyep）**：包括数组和结构体等。
    
3.  **映射类型（Mapping Type）**：键值对数据结构。
    

值类型
---

### 布尔类型

布尔类型是二值变量，取值为 `true` 或 `false`。

        bool public _bool = true;          //定义bool类型变量_b
    

布尔类型的运算符包括：

*   `!` (逻辑非)
    
*   `&&` (逻辑与)
    
*   `||` (逻辑或)
    
*   `==` (相等)
    
*   `!=` (不相等)
    

运算符`||`和`&&`都遵循短路规则，如`f(x) || g(y)`中，如果`f(x)`的值为`true`，那么`g(y)`就不会被执行

        //布尔类型
        bool public _bool = true;          //定义bool类型变量_b
        bool public _bool1 = !_bool;          //非运算
        bool public _bool2 = _bool && _bool1;    //与运算
        bool public _bool3 = _bool || _bool1;    //或运算
        bool public _bool4 = _bool == _bool1;    //相等判断
        bool public _bool5 = _bool != _bool1;    //不相等判断
    

### 整形

`int`/`uint`：分别表示有符号和无符号整形变量。关键字`uint8`到`uint256`（无符号整形，从8位到256）以及`int8`到`int256`，以8位位步长递增（就是按字节为单位增长，`int8`占一个字节，`int16`占两个字节，`int256`占32字节）。`uint`和`int`分别是`uint256`和`int256`的别名。

        //整形
        int public _max_int8 = type(int8).max;      //127
        int public _min_int8 = type(int8).min;      //-128
        uint public _max_uint8 = type(uint8).max;   //255
        uint public _min_uint8 = type(uint8).min;   //0
        int public _max_int16 = type(int16).max;    //32767
        int public _min_int16 = type(int16).min;    //-32768
        uint public _max_uint16 = type(uint16).max; //65535
        uint public _min_uint16 = type(uint16).min; //0
        int public _max_int256 = type(int256).max; 
        int public _min_int256 = type(int256).min;
        uint public _max_uint256 = type(uint256).max;
        uint public _min_uint256 = type(uint256).min;
    

对于整形X，可以使用`type(X).max`和`type(X).min`来获取对应大小。

运算符：

*   比较运算符： `<=`，`<`，`==`，`!=`，`>=`，`>` 返回布尔类型
    
*   位运算符：`&`（与），`|`（或），`^`（异或），`~`（取反） 返回位运算后的值
    
*   移位运算符：`<<`（左移），`>>`（右移） 返回移位后的值
    
*   算数运算符：`+`，`-`，`*`，`/`，`%`，`**`（幂运算） 返回算数运算后的值
    

        //运算符
        uint256 public _number = 1;
        uint256 public _number1 = _number + 1;          //算数运算
        uint256 public _number2 = 2**2;                 //幂运算
        uint256 public _number3 = 7 % 2;                //取余
        int256 public _number4 = ~int256(0);            //取反
        uint256 public _number5 = _number >> 2;         //右移
        uint256 public _number6 = _number << 2;         //左移
        bool public _numberbool = _number2 > _number3;  //比较运算
    

### 地址类型

地址类型有两种大致相同的类型：

*   `address`：保存一个20字节的值（一个以太坊地址的大小）。
    
*   `address payable`：与`address`类型相同，但有额外的方法`transfer`和`send`。
    

这种区别背后的想法是，`address payable`是一个可以发送以太币的地址，`address`是不应该发送以太币的地址，因为它可能是一个合约地址，合约地址不是为了接收以太币而建立的。

类型转换：

允许从`address payable`到`address`的隐式转换，而从`address`到`address payable`的转换必须通过`payable(address)`来实现。

对于`uint160`、整数、`bytes20`和合约类型，允许对`address`进行明确的转换和输出。

只有`address`类型和合约类型的表达式可以通过`payable(……)`显式转换为`address payable`类型。对于合约类型，只有在合约可以接收以太币的情况下才允许这种转换，也就是说，合约要么有一个receive函数，要么有一个payable类型的fallback函数。请注意，`payable(0)`是有效的，是这个规则的例外。

运算符：

*   `<=`，`<`，`==`，`!=`，`>=`和`>`
    

`如果您使用较大字节的类型转换为 address，例如 bytes32，那么 address 就被截断了。为了减少转换的模糊性，从 0.4.24 版本开始，编译器将强迫您在转换中明确地进行截断处理。以32字节的值0x111122333344556677888899AAAABBBBCCCCDDDDEEFFFFCCCC 为例。`

`您可以使用address(uint160(bytes20(b)))，结果是0x111122223333444455556666777788889999aAaa，或者您可以使用 address(uint160(uint256(b)))，结果是 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc。`

        uint256 public _uint256_number = 0x111122333344556677888899AAAABBBBCCCCDDDDEEFFFFCCCC; 
        address public _unit256_address = address(uint160(_uint256_number));             //截取地址
        address public _bytes20_address = address(bytes20(bytes32(_uint256_number)));    //截取地址
    
        address payable public _payable_address = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;    //接收地址
        address payable public _my_address = address(this);                                      //发送地址
    

地址类型成员变量

*   `balance`和`transfer`
    

可以上使用`balance`属性来查询一个地址的以太币余额，也可以使用`transfer`函数向一个地址发送以太币,单位位wei。

        address payable public _receive_address = payable(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2);    //接收地址
        address public _send_address = address(this);                                                     //发送地址
    
        function addressTransfer() public {
            if (_receive_address.balance < 10 && _send_address.balance > 10) {
                _receive_address.transfer(10);  //转账
            }
        }
    

如果当前合约的余额不足，或者以太币转账被接收者拒收，那么`transfer`功能就会失败，`transfer`功能在失败后会还原。

*   `send`
    

`send`是`transfer`的低级对应部分。如果执行失败，当前的合约不会因异常而停止，但`send`会返回`false`.

        function addressSend() public {
                if (_receive_address.balance < 10 && _send_address.balance > 10) {
                    _receive_address.send(10);  //转账,编译带警告，提示用transfer来替换send
    
                }
            }
    

*   `call`，`delegatecall`和`staticcall`
    

为了与不遵守ABI的合约对接，或者为了更直接的控制编码，所以提供了`call`，`delegatecall`和`staticcall`函数。它们都接收一个`bytes memory`参数，并返回是否成功条件`bool`和返回数据`bytes memory`。函数`abi.encode`，`abi.encodePacked`，`abi.encodeWithSelector`和`abi.encodeWithSignature`可以用来编码结构化数据。

### 枚举 enum

枚举（`enum`）是 Solidity 中用户定义的数据类型。它主要用于为 `uint` 分配名称，使程序易于阅读和维护。它与 `C 语言` 中的 `enum` 类似，使用名称来代替从 `0` 开始的 `uint`：

        // 用enum将uint 0， 1， 2表示为Buy, Hold, Sell
        enum ActionSet { Buy, Hold, Sell }
        // 创建enum变量 action
        ActionSet action = ActionSet.Buy;
    

枚举可以显式地和 `uint` 相互转换，并会检查转换的正整数是否在枚举的长度内，否则会报错：

        // enum可以和uint显式的转换
        function enumToUint() external view returns(uint){
            return uint(action);
        }

---

*Originally published on [startha](https://paragraph.com/@starha/jyBsJ4CeNx3dFsDrty33)*
