solidity的数据类型非常重要,这篇文章主要介绍数据类型那些必须知道的知识点,不清楚的同学可以一看究竟。
solidity 的数据类型分为:值类型和引用类型,下面详细的介绍分别有哪些及使用方法。
值类型的变量在赋值或作为参数传递时,会复制整个值。这个分别与 javascript 的概念是相同的。 值类型包括:布尔类型、整数型、地址类型、定长字节数组、枚举、函数。
bool a = true;
bool b = false;
bool resultAnd = a && b; // false
bool resultOr = a || b; // true
bool resultNot = !a; // false
表示非负整数,可以指定位宽(uint8、uint16、uint256...),默认是 uint256。
uint public myUint; // 默认 uint256
uint8 public myUint8;
uint16 public myUint16;
uint256 public myUint256;
表示正负整数,可以指定位宽(int8、int16、uint256),默认 int256。
int public myInt; // 默认 int256
int8 public myInt8;
int16 public myInt16;
int256 public myInt256;
相关安全问题: Solidity 0.8.0 之前整型溢出和下溢是一个常见的问题,为了处理这个问题引入了 safeMath 库;在 solidity 0.8.0 开始,整型运算默认包含了溢出和下溢检查,而不再需要 safeMath 库。
pragma solidity ^0.8.0; contract OverflowExample { uint8 public maxUint8 = 255; function increment() public { maxUint8 += 1; // 这将导致运行时错误,因为 uint8 的最大值是 255 } }
address contractAddress = 0x1234567890123456789012345678901234567890;
address payable recipient = payable(contractAddress);
地址类型有一些特定的方法 用于地址的检查、转账等操作。 | 方法 / 属性 | 说明 |
---|---|---|
balance |
地址的以太币余额,如 address.balance |
|
transfer(uint256 amount) |
向指定地址转账,如 address.transfer(amount) ,转账失败会抛出异常 |
|
send(uint256 amount) |
向指定地址转账,返回布尔值表示是否成功,如 address.send(amount) |
|
call(bytes memory data) |
低级别调用,可用于调用其他合约的函数或发送以太币,如 address.call{value: amount}(data) |
|
delegatecall(bytes memory data) |
委托调用,调用其他合约的代码但使用当前合约的存储,如 address.delegatecall(data) |
|
staticcall(bytes memory data) |
静态调用,不允许修改状态,如 address.staticcall(data) |
用于存储固定长度的字节序列,长度从1到32字节
bytes1 public byte1Array; // 单个字节
bytes2 public byte2Array; // 两个字节
bytes3 public byte3Array; // 三个字节
bytes32 public byte32Array; // 32 个字节
注意:
bytes2 public byte2Array1 = hex"1122";
bytes2 public byte2Array2 = hex"3344";
function compareArrays() public view returns (bool) { return keccak256(byte2Array1) == keccak256(byte2Array2); }
- 当操作定长字节数组时,需要确保索引不超出数组的有效范围,以避免访问越界错误。
- 定长字节数组不支持动态大小调整,因此在使用时需要考虑到存储空间和 gas 成本。
## 5. 枚举类型(enum)
用于定义一组命名的常量值,可增强代码的可读性。
enum Status { Pending, Completed, Cancelled }
Status currentStatus = Status.Pending;
表示函数的类型,可用于将函数作为参数传递或返回函数。有内部函数(只能在合约内部调用)和外部函数(可从合约外部调用)之分。
function add(uint a, uint b) internal pure returns (uint) {
return a + b;
}
function callAdd(function(uint, uint) internal pure returns (uint) func, uint x, uint y) internal pure returns (uint) {
return func(x, y);
}
引用类型的变量存储的是数据的引用,赋值或传递参数时传递的是引用而非整个数据。 用于存储复杂的数据结构或者允许通过引用传递的数据类型。 引用类型包括:变长字节数组、字符串类型、结构体、映射类型、数组。
用于存储可变长度的字节序列,可动态调整长度。
bytes memory data = new bytes(10);
data[0] = 0x01;
用于存储 UTF-8 编码的字符串,是变长字节数组的一种特殊形式。
string memory message = "Hello, World!";
struct Person {
string name;
uint age;
}
Person memory person = Person("Alice", 25);
结构体的使用 结构体可以帮助开发者更有效地组织和管理复杂的数据。它们可以作为函数的参数或返回值,也可以作为其他结构体或映射的成员变量。下面是一些结构体的使用示例:
pragma solidity ^0.8.0;
contract StructUsageExample { struct Employee { string name; uint age; address walletAddress; }
mapping(address => Employee) public employees;
// 添加新员工
function addEmployee(address _employeeAddress, string memory _name, uint _age, address _walletAddress) public {
employees[_employeeAddress] = Employee(_name, _age, _walletAddress);
}
// 获取员工信息
function getEmployee(address _employeeAddress) public view returns (string memory, uint, address) {
Employee memory emp = employees[_employeeAddress];
return (emp.name, emp.age, emp.walletAddress);
}
}
**注意事项**
- 成员变量访问:结构体的成员变量可以通过点号 (.) 访问,例如 myPerson.name。
- 内存与存储:在函数内部使用结构体时,需要注意是否需要在存储区域(storage)或者内存区域(memory)中处理。
- 嵌套结构体:Solidity 支持结构体的嵌套定义,允许在一个结构体中包含另一个结构体作为成员变量。
- Gas 成本:对于复杂的结构体或者包含大量数据的结构体,需要注意 gas 成本和执行效率问题。
## 4. 映射类型
- 用于存储键值对
- 通过 mapping 关键字定义
mapping(address => uint) public balances;
### **映射的特性**
- 键类型:映射的键可以是任何值类型,包括基本类型(如 uint、address)。
- 值类型:映射的值可以是任何 Solidity 支持的数据类型,包括基本类型、复合类型(如 struct)和数组类型。
- 默认值:如果映射中不存在某个键对应的值,则返回该值类型的默认值。例如,uint 类型的默认值是 0,address 类型的默认值是 address(0)。
- Gas 成本:读取映射中的值(查找操作)是 gas 消耗较低的操作,而写入映射中的值(更新操作)可能会消耗更多的 gas,特别是在扩展映射时可能需要大量的 gas。
### 映射的使用场景
映射在 Solidity 合约中有广泛的应用,特别是用于管理状态数据、存储关联数据和实现查找表。以下是一些常见的应用场景:
- 存储账户余额:如上面示例所示,映射可以用来存储多个账户的余额信息。
- ERC20 Token 实现:映射通常用于存储 ERC20 Token 的余额和授权信息。
- 存储关联数据:映射可以用于存储任何需要通过某种键快速查找和访问的关联数据。
- 索引和查找:映射可以作为索引来优化查找和检索操作,例如根据地址查找合约用户的信息。
## 5. 数组
可存储相同类型元素的集合,有定长数组和变长数组之分。
数组在 Solidity 中也被视为引用类型,特别是动态大小的数组。动态大小的数组允许在运行时动态增加或减少其长度,这意味着它们的操作是基于引用的。
### 定长数组(type[N])
定长数组在声明时就需要指定数组的长度 N,且长度不能更改。定长数组通常用于固定大小的数据集合,如固定数量的数据元素存储。
### 动态数组
动态数组是在 Solidity 中比较常见和灵活的数组类型,它的长度可以在运行时动态增加或减少。
```solidity
// 定长数组
uint[3] memory fixedArray = [1, 2, 3];
// 变长数组
uint[] memory dynamicArray = new uint[](5);
特点及注意事项
uint[][] public multiArray;
常量在 Solidity 中是指一旦声明后其值无法更改的数据。常量的声明方式是使用 constant 或 immutable 关键字。主要特点包括:
uint constant public MAX_NUMBER = 100;
变量是 Solidity 中用于存储和管理数据的可变容器。主要特点包括:
uint public count;
使用建议
一次初始化之后不可以修改,定义成 immutable 的变量是可以节省 gas
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!