在 Solidity 中,有各种各样的数据结构可用于组织和处理信息。以下是一些最常用的数据结构。
1. Array
在 Solidity 中,数组(Array)是一种基础的数据结构,它能存储同一类型的多个元素,元素在数组里的顺序由其索引值决定。根据所定义的长度,数组可以分为两种类型:定长和动态。确定长度的数组在创建时固定其大小,之后就不能再改变;动态数组则没有固定的长度,可以添加或删除元素。
创建数组
静态数组的创建方式如下,其中 <Type>
是元素的数据类型,<Size>
是数组长度:
<Type>[<Size>] arrayName;
例如,创建一个长度为5且元素类型为uint
的数组,可以如下创建:
uint[5] myArray;
对于动态数组,其创建方式如下:
代码语言:javascript复制<Type>[] arrayName;
例如,创建一个动态数组,元素类型为uint
:
uint[] myArray;
访问和修改数组中元素
在 Solidity 中,使用数组的索引(从0开始)可以访问或修改数组中的元素。例如:
代码语言:javascript复制myArray[0] = 10; // 修改数组中第一个元素的值为10
uint firstElement = myArray[0]; // 访问数组中的第一个元素
数组的属性和方法
对于数组,有以下一些常用的属性和方法:
•length
属性:返回数组的长度。•push
方法:只适用于动态数组,用于在数组的末尾添加一个元素,同时数组的长度会增加1。•pop
方法:只适用于动态数组,用于删除数组的最后一个元素,同时数组的长度会减少1。
下面的示例中展示了如何在 Solidity 中使用动态数组:
代码语言:javascript复制// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract Test {
uint[] public numArray;
// 添加元素到数组中
function addToArray(uint num) public {
numArray.push(num);
}
// 获取数组的长度
function getArrayLength() public view returns (uint) {
return numArray.length;
}
// 根据索引获取数组中的元素
function getElement(uint index) public view returns (uint) {
return numArray[index];
}
// 移除数组的最后一个元素
function removeLastElement() public {
numArray.pop();
}
}
2. Struct
在Solidity中,结构体(Struct)是一种复杂的数据类型,允许你组合多个不同类型的变量到一个单独的实体。
创建一个结构体的基本语法如下:
代码语言:javascript复制struct StructName {
Type1 variable1;
Type2 variable2;
...
}
其中,“StructName”是你为结构体定义的名字,“Type1”和“Type2”是变量的数据类型(例如 uint、address、string等), “variable1”和“variable2”是这些变量的名字。
以下是一个具体的结构体定义示例:
代码语言:javascript复制struct Student {
uint id;
string name;
uint age;
}
在定义了结构体之后,你可以创建一个新的结构体实例,并初始化其值。例如:
代码语言:javascript复制Student memory newStudent = Student({
id: 1,
name: "Alice",
age: 20
});
注意,在上面的代码块中,“memory”关键字是必需的,表示这个结构体实例是存在于内存中的。
你还可以直接访问和修改结构体的成员变量。例如:
代码语言:javascript复制newStudent.name = "Bob"; // 修改结构体实例中的"name"字段
string studentName = newStudent.name; // 访问结构体实例中的"name"字段
另外,你还可以将结构体存储在数组或者映射中,以实现更复杂的数据管理。例如:
代码语言:javascript复制// 存储在数组中
Student[] public students;
// 存储在映射中,其中地址是键,Student结构体为值
mapping(address => Student) public studentInfo;
下面的示例展示了 Struct 的简单使用场景:
代码语言:javascript复制// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract StructExample {
struct Student {
uint256 id;
string name;
uint256 age;
}
Student[] public students;
function addStudent(
uint256 _id,
string calldata _name,
uint256 _age
) public {
// 3种初始化方式
// 1. 像调用函数一样,初始化时形参的顺序需与结构体字段顺序一致
students.push(Student(_id, _name, _age));
// // 2. key => value形式
// students.push(Student({id: _id, name: _name, age: _age}));
// // 3. 使用临时变量
// Student memory stu;
// stu.age = _age;
// stu.id = _id;
// stu.name = _name;
// students.push(stu);
}
function getStudent(uint256 _index)
public
view
returns (
uint256,
string memory,
uint256
)
{
Student memory stu = students[_index];
return (stu.id, stu.name, stu.age);
}
}
3. Mapping
在 Solidity 中,映射(mapping)是一种关联一个类型的值(键)到另一个类型的值(值)的数据结构,它类似于许多编程语言中的哈希表或字典。映射的键的类型可以是任何基本类型,包括字节和整数类型,但不能是映射、动态数组、合约、枚举和结构。映射的值的类型则几乎没有任何限制,甚至可以是另一个映射。
以下是创建一个映射的基本语法:
代码语言:javascript复制mapping(_KeyType => _ValueType) public mappingName;
在这里,_KeyType
是键的数据类型,_ValueType
是值的数据类型,并且public
关键词使得映射可以被合约以外的程序读取(但无法修改)。
举个例子,以下代码创建了一个名为balances
的映射,它将地址映射到uint
值:
mapping(address => uint) public balances;
在创建了映射之后,可以使用中括号[]
来访问或修改映射中的元素,
balances[address1] = 100; // 设置地址address1 的余额为100
uint balance = balances[address1]; // 获取地址address1 的余额
需要注意的是,映射在默认情况下所有键都存在且对应的值默认为类型的初始值,如对应uint
的默认是0
,对应bool
的默认为false
。
以下是一个更完整的使用映射管理账户余额的 Solidity 合约示例:
代码语言:javascript复制// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract MyContract {
// 定义一个映射,用来存储每个地址对应的余额
mapping(address => uint) public balances;
// 存款
function deposit(uint amount) public {
// 增加发送者的余额
balances[msg.sender] = amount;
}
// 获取余额
function getBalance() public view returns (uint) {
return balances[msg.sender];
}
}
4. Enum
在Solidity中,枚举类型(enum)是由开发者定义的一种特殊类型,它允许你创建一组预定义的值。枚举可以被看作是一种限制了值的类型,这有助于使代码更加清晰易懂,减少错误。
以下是定义一个枚举类型的基本语法:
代码语言:javascript复制enum EnumName {
Value1,
Value2,
...
}
在这里,“EnumName”是你为枚举定义的名字,“Value1”和“Value2”等则是枚举中的值。
以下是一个实际的枚举定义示例:
代码语言:javascript复制enum State {
Created,
Locked,
Inactive
}
在此例中,State
是枚举的名字,而 Created
、Locked
和 Inactive
则是该枚举中的值。
一旦定义了一个枚举类型,就可以在合约中创建该类型的变量,并将其设置为该枚举中的值。例如:
代码语言:javascript复制State public state = State.Created;
在上面的代码段中,有一个公开的 State
类型的状态变量,它的初始值被设置为Created
。
你还可以在合约的函数中修改或检查这个枚举类型的变量:
代码语言:javascript复制function makeInactive() public {
state = State.Inactive; // 修改枚举变量的值
}
function checkState() public view returns(bool) {
return state == State.Inactive; // 检查枚举变量的值
}
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)[1]进行许可,使用时请注明出处。 Author: mengbin[2] blog: mengbin[3] Github: mengbin92[4] cnblogs: 恋水无意[5] 腾讯云开发者社区:孟斯特[6]
References
[1]
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0): https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh
[2]
mengbin: mengbin1992@outlook.com
[3]
mengbin: https://mengbin.top
[4]
mengbin92: https://mengbin92.github.io/
[5]
恋水无意: https://www.cnblogs.com/lianshuiwuyi/
[6]
孟斯特: https://cloud.tencent.com/developer/user/6649301