Array
contract Demo {
// 固定大小的数组
uint[3] public fixedArray; // [0, 0, 0]
uint[] public arr = new uint[](3); // [0, 0, 0]
// 动态大小的数组
uint[] public dynamicArray; // []
}
操作动态大小的数组:
// 获取数组长度
function getLength() public view returns (uint) {
return dynamicArray.length;
}
// 获取指定元素
function get(uint _index) public view returns (uint) {
return dynamicArray[_index];
}
// 添加元素
function push(uint _value) public {
dynamicArray.push(_value);
}
// 更新指定元素
function set(uint _index, uint _value) public {
dynamicArray[_index] = _value;
}
// 删除指定元素; eg: [1, 2, 3] - [1, 0, 3]
function deleteByIndex(uint _index) public {
delete dynamicArray[_index]; // 注意: 这里是将该元素重置为默认值了, 不会改变数组的长度
}
// 删除最后一个元素; eg: [1, 2, 3] - [1, 2]
function pop() public {
dynamicArray.pop();
}
// 删除指定元素; eg: [1, 2, 3] - [1, 3]
function remove(uint _index) public {
for (uint i = _index; i < dynamicArray.length - 1; i++) {
dynamicArray[i] = dynamicArray[i + 1];
}
dynamicArray.pop();
}
// 删除所有元素; eg: [1, 2, 3] - []
function clear() public {
delete dynamicArray; // 注意: 这里是将数组重置为空数组了, 数组长度变为 0
}
操作固定大小的数组:
// 获取数组长度
function getLength() public view returns (uint) {
return fixedArray.length;
}
// 获取指定元素
function get(uint _index) public view returns (uint) {
return fixedArray[_index];
}
// 更新指定元素
function set(uint _index, uint _value) public {
fixedArray[_index] = _value;
}
// 删除指定元素; eg: [1, 2, 3] - [1, 0, 3]
function deleteByIndex(uint _index) public {
delete fixedArray[_index]; // 注意: 这里是将该元素重置为默认值了, 不会改变数组的长度
}
// 删除所有元素; eg: [1, 2, 3] - []
function clear() public {
delete fixedArray; // 注意: 这里是将所有元素重置为默认值了, 不会改变数组的长度
}
在内存中创建数组:
contract Demo {
function createArray(uint256 size) public pure returns (uint256[] memory) {
uint256[] memory arr = new uint256[](size);
for (uint256 i = 0; i < size; i++) {
arr[i] = i;
}
return arr;
}
}
demo - 接受一个整数数组和一个索引作为参数,移除索引指定的元素并返回新数组:
function removeAtIndex(
uint[] memory arr,
uint index
) public pure returns (uint[] memory) {
uint[] memory newArr = new uint[](arr.length - 1);
for (uint i = 0; i < arr.length; i++) {
if (i < index) {
newArr[i] = arr[i];
} else if (i > index) {
newArr[i - 1] = arr[i];
}
}
return newArr;
}
如果可以打乱数组的顺序,某些情况下可以考虑将想删除的元素与数组最后一位元素交换,然后调用 pop 方法:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
contract Demo {
uint[] public arr = [1, 2, 3, 4, 5];
function removeAtIndex1(uint _index) public {
for (uint i = _index; i < arr.length - 1; i++) {
arr[i] = arr[i + 1];
}
arr.pop();
}
function removeAtIndex2(uint _index) public {
arr[_index] = arr[arr.length - 1];
arr.pop();
}
}
Mapping
contract Demo {
// 定义一个 address => uint 的 mapping
mapping(address => uint) public myBalance;
// 获取指定值
function getMyBalance() public view returns (uint) {
return myBalance[msg.sender]; // 如果没有设置过该值, 则返回类型的默认值
}
// 添加/修改指定值
function setMyBalance(uint _amount) public {
myBalance[msg.sender] += _amount; // 如果没有设置过, 则基于类型的默认值进行更新
}
// 删除指定值
function deleteMyBalance() public {
delete myBalance[msg.sender]; // 重置为类型的默认值
}
}
嵌套 mapping :
contract Demo {
// 定义一个嵌套的 mapping
mapping(address => mapping(address => uint)) public allowance;
// 获取指定值
function getAllowance(
address _owner,
address _spender
) public view returns (uint) {
return allowance[_owner][_spender];
}
// 新增/修改指定值
function setAllowance(address _spender, uint _amount) public {
allowance[msg.sender][_spender] = _amount;
}
// 删除指定值
function deleteAllowance(address _spender) public {
delete allowance[msg.sender][_spender];
}
}
demo - 简单的银行账户系统:
contract SimpleBank {
mapping(address => uint) private balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
function checkBalance() public view returns (uint) {
return balances[msg.sender];
}
}
demo - 实现可迭代映射:
contract Demo {
mapping(address => uint) public balance;
mapping(address => bool) public isCustomer;
address[] public customers;
function deposit(address _customer, uint _amount) public {
balance[_customer] += _amount;
if (!isCustomer[_customer]) {
customers.push(_customer);
isCustomer[_customer] = true;
}
}
function getCustomerBalance(address _customer) public view returns (uint) {
require(isCustomer[_customer], "Customer does not exist");
return balance[_customer];
}
function getCustomerBalanceByIndex(uint _index) public view returns (uint) {
require(_index < customers.length && _index >= 0, "Index out of bounds");
return balance[customers[_index]];
}
}
Struct
创建 Struct 实例:
contract Demo {
struct Student {
uint id;
string name;
}
Student[] public students;
function addStudent1(string memory _name) public {
// 按属性顺序创建 Struct 实例, 并添加到 students 数组
students.push(Student(students.length, _name));
}
function addStudent2(string memory _name) public {
// 按属性名创建 Struct 实例, 并添加到 students 数组
students.push(Student({id: students.length, name: _name}));
}
function addStudent3(string memory _name) public {
// 创建 Struct 实例, 但不指定属性值, 会使用默认值
Student memory student;
// 设置属性值
student.id = students.length;
student.name = _name;
// 添加到 students 数组
students.push(student);
}
}
访问 Struct 实例属性:
function getStudentInfoByIndex(
uint _index
) public view returns (uint, string memory) {
Student memory student = students[_index];
return (student.id, student.name);
}
修改 Struct 实例属性:
function updateStudentNameByIndex(uint _index, string memory _name) public {
Student storage student = students[_index];
student.name = _name;
}
删除 Struct 实例属性:
function deleteStudentNameByIndex(uint _index) public {
Student storage student = students[_index];
delete student.name; // 将属性值重置为类型默认值
}
删除 Struct 实例:
function deleteStudentByIndex(uint _index) public {
delete students[_index]; // 将该 Struct 实例的属性值都重置为对应类型默认值
}
Enum
枚举值在内部表示为无符号整数,从 0 开始递增。枚举的默认值是其定义中的第一个值。
contract Demo {
enum State {
PENDING, // 0
ACTIVE, // 1
INACTIVE // 2
}
State public state; // 默认值为 PENDING, 即 0
// 更新 state
function updateState(State _state) public {
state = _state;
}
// 重置 state
function resetState() public {
delete state; // 重置为默认值 PENDING, 即 0
}
// 获取 state
function getState() public view returns (State) {
return state;
}
}