Solidity 是一种静态类型语言,这意味着每个变量(状态变量和局部变量)都需要在编译时指定变量的类型。

Solidity 提供了几种基本类型,并且基本类型可以用来组合出复杂类型。

除此之外,类型之间可以在包含运算符号的表达式中进行交互。

“​​undefined​​​”或“​​null​​​”值的概念在Solidity中不存在,但是新声明的变量总是有一个 默认值 ,具体的默认值跟类型相关。 要处理任何意外的值,应该使用错误处理来恢复整个交易,或者返回一个带有第二个​​bool​​ 值的元组表示成功。

bool/布尔类型

布尔值的取值范围为 true 和 false 。

默认值:​​false​

pragma solidity ^0.8.0;contract TestBool {error NotEqual(bool A,bool B);bool public A; // falsebool public B = true; //true// require(A==B,"A not equal B");if (A != B) {error NotEqual(A,B);}}

运算符:

  • ​!​​(逻辑非)
  • ​&&​​ (逻辑与, “and” )
  • ​||​​ (逻辑或, “or” )
  • ​==​​ (等于)
  • ​!=​​ (不等于)

int、uint/整数类型

int 有符号整型

默认为​​int256​

不同位长的整形范围如下:

  • ​int8​​ 取值范围:-(2 ** 7)到 2 ** 7 -1
  • ​int16​​取值范围:-(2 ** 15)到 2 ** 15 -1
  • ​intX​​取值范围:-(2**​​X​​​-1)到 2**(​​X​​-1) -1
  • ​int256​​取值范围:-(2 ** 255)到 2 ** 255 -1

uint 无符号整型

默认为​​uint256​

不同位长的整形范围如下:

  • ​uint8​​取值范围:0 到 2 ** 8 – 1
  • ​uint16​​取值范围:0 到 2 ** 16 – 1
  • ​uintX​​取值范围:0 到 2 ** ​​X​​ – 1
  • ​uint256​​取值范围:0 到 2 ** 256 – 1

运算符:

  • 比较运算符: <= , = , > (返回布尔值)
  • 位运算符: & , | , ^ (异或), ~ (位取反)
  • 移位运算符: <> (右移位)
  • 算数运算符: + , – , 一元运算负 – (仅针对有符号整型), * , / , % (取余或叫模运算) , ** (幂)

对于整形 X,可以使用 type(X).min 和 type(X).max 去获取这个类型的最小值与最大值。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract TestIntval {int8 public i8 = -1;int public i256 = 456;int public i = -123; // int 等同于 int256// int 的最大最小值int public minInt = type(int).min;int public maxInt = type(int).max;uint8 public u8 = 1;uint256 public u256 = 456;uint public u = 123; // uint等同于 uint256 // uint 的最大最小值uint public minUInt = type(uint).min;uint public maxUInt = type(uint).max;function mini() public pure returns(uint8){return type(uint8).max;}}

0.8.0 开始,算术运算有两个计算模式:一个是 “wrapping”(截断)模式或称 “unchecked”(不检查)模式,一个是”checked” (检查)模式。 默认情况下,算术运算在 “checked” 模式下,即都会进行溢出检查,如果结果落在取值范围之外,调用会通过 失败异常 回退。 你也可以通过 ​​unchecked { ... }​​切换到 “unchecked”模式

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.8.0;contract C {function f(uint a, uint b) pure public returns (uint) {// 减法溢出会返回“截断”的结果unchecked { return a - b; }}function g(uint a, uint b) pure public returns (uint) {// 溢出会抛出异常return a - b;}}

调用 ​​f(2, 3)​​​将返回 ​​2**256-1,​​​ 而​​ g(2, 3)​​ 会触发失败异常。

​unchecked​​ 代码块可以在代码块中的任何位置使用,但不可以替代整个函数代码块,同样不可以嵌套。

此设置仅影响语法上位于 ​​unchecked​​ 块内的语句。 在块中调用的函数不会此影响。

address/地址

默认值: 0x0000000000000000000000000000000000000000

运算符:

  • <=, = and >

示例:

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract TestAddress {//与其他机器语言相区别的类型就是这个address 类型,160-bit/20byteaddress public myAddr = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;//合约自己的地址address contractAddress = address(this);//跟普通的地址类型一样,但多了两个方法 transfer/send 这两个方法后面章节会讲到// address sender = payable(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4);//可以使用 balance 属性来查询一个地址的余额function getBalance()public viewreturns (uint256, uint256){require(myAddr.balance < contractAddress.balance, "1 must lg 2");return (myAddr.balance, contractAddress.balance);}}

bytes/字节数组

在计算机中的最小存储单位是 bit(位)

  • 1byte等于8位
  • Solidity中,byte可以赋值为
  • 16进制数字
  • 单引号的单个或多个字符

定长字节数组

bytes1 后面数字1是表示1字节 bytes默认等于bytes1
Bytes2 后面数字2是表示2字节
Bytes3 后面数字3是表示3字节
bytes4 后面数字4是表示4字节

bytes32 后面数字32是表示32字节

bytes32 等价于 int256或uint256 的位数

运算符

  • 比较运算符: <=, =, > (返回布尔型)
  • 位运算符: &, |, ^ (按位异或), ~ (按位取反)
  • 移位运算符: <> (右移位)
  • 索引访问:如果 x 是 bytesI 类型,那么 x[k] (其中 0 <= k < I)返回第 k 个字节(只读)。

成员变量

​.length​​ 表示这个字节数组的长度(只读)

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract BytesTest {//定长字节数组,长度不可变bytes1 public num1 = 0x12;// bytes1 public num1 = 0x112; 溢出最大长度,这样会报错// 也可以写成字符串类型bytes4 public num2 = "0x12";//也支持直接写 16 进制bytes4 public num3 = 0x12121212;//不足位的补0bytes32 public num4 = 'abc';//0x6162630000000000000000000000000000000000000000000000000000000000function getlength1() public view returns (uint8) {return num1.length;}function getlength2() public view returns (uint8) {return num2.length;}}

string/字符串

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract TestString {string public myString = "hello";string public myStringUnicl = unicode"你好"; //unicode 编码string public myStringUnicl2 = unicode"你好"; //unicode 编码// 两个字符串连接用 concatfunction strConcat(string memory _a, string memory _b)publicpurereturns (string memory){return string.concat(_a, _b);}// 也可以转成bytes,bytes 和 string 可以互转function bytesConcat(string memory _a, string memory _b) public pure returns (string memory){bytes memory _ba = bytes(_a);bytes memory _bb = bytes(_b);bytes memory ret = bytes.concat(_ba,_bb);return string(ret);}}

enum/枚举

枚举可以在合约之外声明,也可在合约内声明.

默认取值为第一个元素的值

contract UserState {// 枚举//默认值是列表中的第一个元素enum State { Online, // 0Offline,// 1Unknown // 2} Status public status;function get() public view returns (Status) {return status;}// 通过将uint传递到输入来更新状态function set(Status _status) public {status = _status;}// 也可以是这样确定属性的更新function off() public {status = Status.Offline;}// delete 将枚举重置为其第一个值 0function reset() public {delete status;}}

struct/结构体

您可以通过创建结构来定义自己的类型。

它们用于将相关数据分组在一起。

结构可以在合约之外声明,也可以在另一个合约中导入。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract Structs {struct Todo {string text;bool completed;}// 结构体数组Todo[] public todos;// 初始化结构的3种方法function create(string calldata _text) public {// 1.像函数一样调用它todos.push(Todo(_text, false));// 2. 键值对todos.push(Todo({text: _text, completed: false}));// 3.初始化一个空结构,然后更新它Todo memory todo;todo.text = _text;todos.push(todo);// completed 没有定义,默认为 false}//通过索引获取结构体数组中一个元素,并更新内部的属性function update(uint _index) public {Todo storage todo = todos[_index];todo.completed = !todo.completed;}}

mapping/映射

映射是使用语法映射(keyType=>valueType)创建的。

keyType可以是任何内置值类型、字节、字符串或任何约定。

valueType可以是任何类型,包括另一个映射或数组。

映射不可迭代。

// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract Mapping {//从地址到uint的映射mapping(address => uint) public myMap;function get(address _addr) public view returns (uint) {//映射始终返回一个值。//如果从未设置该值,它将返回默认值。return myMap[_addr];}// 更新此地址的值function set(address _addr, uint _i) public {myMap[_addr] = _i;}function remove(address _addr) public {//将值重置为默认值delete myMap[_addr];}}//嵌套 mappingcontract NestedMapping {//嵌套映射(从地址映射到另一个映射)mapping(address => mapping(uint => bool)) public nested;function get(address _addr1, uint _i) public view returns (bool) {// 可以从嵌套映射中获取值return nested[_addr1][_i];}function set(address _addr1,uint _i,bool _boo) public {nested[_addr1][_i] = _boo;}// 删除 mapping 的一个元素function remove(address _addr1, uint _i) public {delete nested[_addr1][_i];}}

array/数组

初始化数组的几种方法

//初始化数组的几种方法uint256[] public arr;uint256[] public nums = [1, 2, 3];//定长数组,所有元素初始化为 0uint256[10] public myFixedSizeArr;//未定义初始值的元素默认为 0uint256[3] public three = [4, 5];// 直接打印数组列表;function getNums()externalviewreturns (uint256[] memory,uint256[] memory,uint256[10] memory, uint256[3] memory){return (arr, nums, myFixedSizeArr,three);}

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract Array {//初始化数组的几种方法uint256[] public arr;uint256[] public nums = [1, 2, 3];//定长数组,所有元素初始化为 0uint256[10] public myFixedSizeArr;uint256[3] public three = [4, 5, 6];// 获取数组长度function getLen() external view returns (uint256) {return nums.length;}//向数组中添加值function pushIndex(uint256 _x) external {nums.push(_x);}// 这样删除数组不会改变数组长度,被删除的数字索引值会变成 0function deleteIndex(uint256 _x) external {delete nums[_x];}//不改变数组顺序情况下删除数组//通过循环删除数组索引 [1,2,3,4] => [1,3,4,4] => [1,3,4]function removeIndex(uint256 _x) public {require(_x < nums.length, "out of index");for (uint256 i = _x; i  [1,4,3,4]=>[1,4,3]function removeIndex2(uint256 _x) public {require(_x < nums.length, "out of index");nums[_x] = nums[nums.length - 1];nums.pop();}//移除数组最后一个元素function pop() external {nums.pop();}//方法测试function testRemove() external {nums = [1, 2, 3, 4];removeIndex(2);assert(nums[0] == 1 && nums[1] == 2);assert(nums[2] == 4);assert(nums.length == 3);}}