Arrays — push, pop, итерация
Как использовать массивы в Solidity: добавлять элементы через push, удалять последний через pop и обходить массив циклом.
Массив хранит список значений
Array в Solidity — это упорядоченный список. У каждого элемента есть индекс, а у массива есть length.
Массив подходит, когда нужно сохранить порядок: список задач, список участников, историю действий или набор адресов, который потом надо прочитать целиком.
Пишем список задач
Создайте файл contracts/TaskList.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract TaskList {
struct Task {
string text;
bool completed;
address createdBy;
}
Task[] private tasks;
event TaskAdded(uint256 indexed index, string text, address indexed createdBy);
event TaskCompleted(uint256 indexed index);
event LastTaskRemoved(uint256 indexed index);
error EmptyText();
error InvalidIndex(uint256 index);
error EmptyArray();
function addTask(string calldata text) external {
if (bytes(text).length == 0) {
revert EmptyText();
}
tasks.push(
Task({
text: text,
completed: false,
createdBy: msg.sender
})
);
emit TaskAdded(tasks.length - 1, text, msg.sender);
}
function completeTask(uint256 index) external {
if (index >= tasks.length) {
revert InvalidIndex(index);
}
tasks[index].completed = true;
emit TaskCompleted(index);
}
function removeLastTask() external {
if (tasks.length == 0) {
revert EmptyArray();
}
uint256 lastIndex = tasks.length - 1;
tasks.pop();
emit LastTaskRemoved(lastIndex);
}
function getTask(uint256 index) external view returns (Task memory) {
if (index >= tasks.length) {
revert InvalidIndex(index);
}
return tasks[index];
}
function taskCount() external view returns (uint256) {
return tasks.length;
}
function getAllTasks() external view returns (Task[] memory) {
return tasks;
}
function countCompletedTasks() external view returns (uint256 completedCount) {
uint256 length = tasks.length;
for (uint256 i = 0; i < length; i++) {
if (tasks[i].completed) {
completedCount++;
}
}
}
}Этот контракт хранит задачи в массиве, добавляет новые через push, удаляет последнюю через pop и проходит по массиву циклом, чтобы посчитать выполненные задачи.
Как это работает
Task[] private tasks — динамический массив структур. Его длина меняется во время работы контракта.
tasks.push(...) — добавляет новый элемент в конец массива. После push индекс нового элемента равен tasks.length - 1.
tasks[index] — читает или изменяет элемент по индексу. Индексы начинаются с 0, поэтому последний элемент находится по индексу tasks.length - 1.
tasks.pop() — удаляет последний элемент и уменьшает length на 1. pop не умеет удалить элемент из середины массива.
for (uint256 i = 0; i < length; i++) — проходит по всем элементам массива. В примере цикл находится в view-функции, поэтому он не меняет состояние и не стоит gas при обычном чтении через RPC.
Task memory — копия задачи из storage в память. Такую копию удобно вернуть из view-функции наружу.
Что важно знать про массивы
Динамический массив в storage хранит length и элементы. Solidity проверяет выход за границы: если обратиться к tasks[999], когда элементов меньше, вызов откатится.
Большие массивы опасно обходить в транзакциях. Чем больше элементов в цикле, тем больше gas. Если массив станет слишком большим, транзакция может перестать помещаться в block gas limit.
getAllTasks() удобно для маленьких списков и локальных примеров. Для больших данных лучше читать элементы постранично: сначала taskCount(), затем getTask(index) для нужного диапазона.
Частые ошибки
Удалять через pop не тот элемент → pop удаляет только последний элемент. Для удаления из середины нужен отдельный паттерн: сдвиг элементов или замена удаляемого элемента последним.
Итерировать большой массив в write-функции → такой вызов может стать слишком дорогим или начать падать по gas. Ограничивайте размер массива или делайте обработку частями.
Забывать проверку индекса → перед чтением tasks[index] проверяйте index < tasks.length, чтобы вернуть понятную ошибку вместо низкоуровневого отката.
Что дальше
- Mapping и вложенные маппинги — сравните массивы со storage по ключу
- Деплой контракта — задеплойте
TaskListи вызовите его функции - Вызов write-функций — отправьте
addTask,completeTaskиremoveLastTaskчерез ethers v6