Перейти к содержанию

Массивы

Массив — это последовательность однородных элементов. ZScript предоставляет два встроенных вида массивов: статический (ограниченный, под который память выделяется заранее) и динамический.

Статический массив

Объявляется следующим образом:

// тип_переменных название_массива[ число_элементов ];

int hitpoints[ 5 ]; // Пять элементов типа "int" в массиве с названием "hitpoints".

Actor tempActors[ 200 ]; // Двести акторов в массиве с названтем "tempActors".

По умолчанию инициализирован наиболее нейтральными значениями: "0" для целочисленных и чисел с плавающей точкой и NULL для указателей.

Индексы формируются от нуля до <указанного числа минус один>. Доступ к элементу и для чтения, и для записи осуществляется путём добавления нужного индекса в квадратных скобках:

int hitpoints[ 5 ];

hitpoints[ 0 ] = 7;
hitpoints[ 1 ] = 4;
hitpoints[ 2 ] = hitpoints[ 0 ]; // 7.
hitpoints[ 3 ] = 4 + 3 * 6; // 22.

for ( int i = 0; i < 5; i++ ) {
    console.printf( "hp[ " .. i .. "]: " .. hitpoints[ i ] );
    // "hp[ 0 ] = 7",
    // "hp[ 1 ] = 4",
    // "hp[ 2 ] = 7",
    // "hp[ 3 ] = 22",
    // "hp[ 4 ] = 0".
}

При попытке выхода за пределы массива VM выкинет исключение "out of bounds (max #, cur #)".

Также есть возможность указывать значения при инициализации и автоматически определять длину получившегося списка, если не указывать число в квадратных скобках, но в ZScript эта механика, по-видимому, не до конца доделана, и поэтому применяться может лишь в специфических случаях:

static const String weapons[] = {
    "Pistol", "Chaingun",
    "Shotgun", "SSG",
    "Rocket launcher",
    "Plasmagun", "BFG9000"
};

Динамический массив

Встроенная реализация массива с изменяемой длиной (аналог Vector из C++). Используется, когда число элементов заранее не может быть известно. Все методы, связанные с ним, можно посмотреть в файле "dynarrays.zs".

// Array<тип_данных> название;

// Например:
Array<int> myDynamicIntegerArray;
Array<Actor> actorsToRemove;
Array<double> someValues;

Изначально массив пуст всегда и его длина равна нулю. Проинициализировать значениями даже через фигурные скобки его не удастся.

Добавление нового элемента производится через метод "Push( значение )" (добавляет в конец) или через "Insert( куда, значение )":

Array<int> integers;

integers.Push( 3 );
integers.Push( 17 );
integers.Push( -2 );
integers.Push( 21 );      // 3, 17, -2, 21.
integers.Insert( 0, 4 );  // 4, 3, 17, -2, 21.
integers.Insert( 3, -9 ); // 4, 3, 17, -9, -2, 21.
integers.Push( 17 );      // 4, 3, 17, -9, -2, 21, 17.

Максимальное число элементов

Технически и этот массив ограничен по длине, количеством доступной оперативной памяти или 4.2 миллиардами элементов (...смотря что закончится раньше). Но чтобы его заполнить хотя бы наполовину, нужно писать крайне кривой код. Ну или целенаправленно саботировать язык.

Доступ на чтение и запись существующих элементов осуществляется как у обычного массива — через квадратные скобки. Чтобы получить текущую длину массива, необходимо использовать функцию "uint Size()".

integers[ 1 ] = 4;
integers[ 5 ] = 888;

for ( int i = 0; i < integers.Size(); i++ ) {
    console.printf( "" .. integers[ i ] );
    // 4, 4, 17, -9, -2, 888, 17.
}

Для удаления существующих элементов есть метод "Delete( откуда, сколько )". Очищением всего списка занимается метод "Clear()".

integers.Delete( 1, integers.Size() - 2 );
// Удаление всего, кроме первого и последнего элементов.

console.printf( "Array size: " .. integers.Size() );
// "Array size: 2".

for ( int i = 0; i < integers.Size(); i++ ) {
    console.printf( "" .. integers[ i ] );
    // 4, 17.
}

integers.Clear();
console.printf( "Array size: " .. integers.Size() );
// "Array size: 0".

Также есть несколько других функций: "uint Find( что_искать )" (последовательно ищет указанный элемент и возвращает индекс первого совпадения, и "Size()", если не найдено), "bool Pop()" (попытаться удалить последний элемент).

Перемещение и копирование массивов

Присваивать массивы друг другу через оператор "=" невозможно, компилятор вылетит с ошибкой "Cannot assign dynamic arrays, use Copy() or Move() function instead".

Для того, чтобы оперировать присвоением, как подсказывает компилятор, есть методы "Copy( откуда_копировать )", "Move( откуда_перемещать )" и, с версии GZDoom 4.2.0, "Append( откуда_добавлять )".

При выходе за границы динамического массива VM вылетит с тем же исключением, что было и в статическом.

Многомерный динамический массив

Для создания многомерного динамического массива можно использовать промежуточный класс:

class ArrayCellX {
    Array<int> cellsY;
}

Array<ArrayCellX> cellsX;

// <...>

cellsX[ 4 ].cellsY[ 5 ] = 47;

Также старые версии имели трудности с прокладыванием пути в многомерных динамических массивах. В случае возникновения такого недоразумения стоит использовать промежуточную ячейку:

ArrayCellY cury = cellsX[ 4 ];

cury.cellsY[ 5 ] = 47;