WarCraft 3: 5. Обобщенные типы

WurstScript

Классы

Обобщенные типы - концепция, предоставляющая возможность абстрагироваться от работы с конкретными типами. Фактически, она позволяет избавится от необходимости дублировать код программы в случае, если работа с разными типами данных подчиняется одним и тем же правилам.
В качестве примера можно привести некий класс List — контейнер, хранящий в себе коллекцию данных определенного типа.
В классическом случае, если бы мы хотели, чтобы контейнер List мог содержать набор экземпляров некоего класса A, нам бы пришлось написать класс List для хранения непосредственно экземпляров класса A, назовем его ListOfA
class A

// Класс-контейнер для хранения экземпляров класса A
class ListOfA
    // Добавляет элемент в список
    function add(A element)
        ...
    // Удаляет элемент из списка
    function remove(A element)
        ...
    // Возвращает кол-во элементов в списке
    function size() returns int
        ...
Если бы нам так же потребовались контейнеры для хранения экземпляров классов B, C, D и т.д., нам бы пришлось написать аналогичные контейнеры для каждого из этих классов — ListOfB, ListOfC, ListOfD и т.д. При этом, алгоритм работы с каждым из контейнеров был бы идентичен, различался бы только тип хранимых данных.
Используя обобщенные типы мы можем избежать столь однотипной рутины. Нам достаточно указать параметр типа, который будет использоваться повсюду в теле класса. Этот параметр указывается в угловых скобках <> и впоследствии применяется в теле класса
// Класс-контейнер для хранения экземпляров произвольного типа
class List<T>
    // Добавляет элемент в список
    function add(T element)
        ...
    // Удаляет элемент из списка
    function remove(T element)
        ...
    // Возвращает кол-во элементов в списке
    function size() returns int
        ...
Теперь мы можем использовать класс List с конкретным типом, посредством следующего синтаксиса
// Создание списка для экземпляров AnyClass
List<AnyClass> list = new List<AnyClass>
// Добавление экземпляра AnyClass в список
AnyClass x = new AnyClass(...)
list.add(x)
Обобщенные типы в Wurst могут быть связанны только с типом int и пользовательскими классами (так как классы имеют свой целочисленный, уникальный typeId).
Если у вас существует необходимость связать обобщенный тип с одним из встроенных типов, вам необходимо определить функции его преобразования в целое. Такие функции объявляются посредством следующего синтаксиса
function [TYPE]ToIndex([TYPE] t) returns int

function [TYPE]FromIndex(int index) returns [TYPE]
В стандартной библиотеке предусмотрен пакет TypeCasting, реализующий набор необходимых функций. Например для типа unit
function unitToIndex(unit u) returns int
    return u.getHandleId()

function unitFromIndex(int index) returns unit
    data.saveFogState(0,ConvertFogState(index))
    return data.loadUnit(0)
Для лучшего понимания принципа работы обобщенных типов Wurst обратитесь за примерами в пакеты TypeCasting и HashList стандартной библиотеки.
Прим. Пер.: Обобщенные типы Wurst далеки от совершенства, пока я работал над этой частью статьи мне приходилось регулярно натыкаться на баги, в виде падения компилятора либо отсутствия какого-либо желания загружаться со стороны карты. Я бы рекомендовал использовать обобщенные типы только если вы действительно знаете, что вы делаете и как это работает изнутри (в особенности это касается базовых типов).

Функции

Прим. Пер.: Чтобы лучше понять примеры приведенные ниже, следует ознакомиться с главой "Lambda выражения"
Функции так же могут использовать обобщенные типы. Параметр типа, в таком случае, указывается после имени функции.
Функция forall в следующем примере проверяет каждый элемент списка на истинность некоторому "утверждению". Функция должна быть обобщенной, так как работает с любым типом списка
function forall<T>(LinkedList<T> l, LinkedListPredicate<T> pred) returns boolean
    for x in l
        if not pred.isTrueFor(x)
            return false
    return true

// Применение:
LinkedList<int> l = ...
// Проверка четности всех элементов списка
if forall<int>(l, (int x) -> x mod 2 == 0)
    print("true")
Во время вызова обобщенной функции параметр типа может быть опущен, если его можно спрогнозировать из передаваемых аргументов
...
if forall(l, (int x) -> x mod 2 == 0)
    ...
Расширяющие функции (см. соответствующую главу) так же могут быть обобщенными
function LinkedList<T>.forall<T>(LinkedListPredicate<T> pred) returns boolean
    for x in this
        if not pred.isTrueFor(x)
            return false
    return true

...
if l.forall((int x) -> x mod 2 == 0)
        ...

Просмотров: 24

Комментарии пока отсутcтвуют