WarCraft 3: 3. Пакеты

WurstScript

Определение

Как говорилось ранее, любой Wurst-код должен располагаться внутри пакета. Пакеты, в свою очередь, определяют организацию кода и пространства имен. Глобальное пространство имен, это пространство имен самого пакета, вне какого-либо блока кода (функции/класса/модуля и т.д.).
Правила определения пакетов могут различаться от инструментов и подходов, которые вы применяете.
Если вы используете внешний редактор Visual Studio Code, вы должны придерживаться правила именования файлов исходного кода — файл должен иметь такое же имя, как и содержащийся в этом файле пакет
// Файл содержащий пакет SomePackage должен иметь имя SomePackage.wurst
package SomePackage

...

init
    ...
Если файл содержит несколько пакетов (что не рекомендуется), каждый пакет должен заканчиваться ключевым словом endpackage
package SomePackage1

...

init
    ...

endpackage

package SomePackage2

...

init
    ...

endpackage
Если вы работаете с Wurst посредством редактора карт WurstWE, вы так же вынуждены использовать ключевое слово endpackage в конце каждого пакета.

import

Пакет может импортировать другие пакеты, для получения доступа к их ресурсам (переменным/функциям/классам и т.д.), которые объявлены публичными (public). Импорт пакетов должен производиться в начале пакета, сразу после его объявления
package MyPackage
// Импорт пакетов
import SomePackage
import AnotherPackge
import public PackageX // public импорт пакета (смотреть далее)

import public
По умолчанию, ресурсы импортированные из другого пакета не экспортируются импортирующим пакетом
package A
public constant x = 5

package B
import A
var y = x

package C
import B
var z = x // Ошибка!
Переменная x была импортирована пакетом B из пакета A, в результате чего, внутри пакета B можно получить к ней доступ. Однако, пакет B не экспортирует переменную x, поэтому ее использование в пакете C, который импортирует пакет B, невозможно.
Мы можем исправить эту ситуацию, путем включения пакета A в пакет C, но возможно вам придется избегать подобного подхода. Использование публичного импорта решит проблему. Такой вид импорта позволяет пакету экспортировать всё, что было им импортировано
package A
public constant x = 5

package B
import public A
var y = x

package C
import B
constant z = x // Все хорошо
Теперь пакет C имеет доступ к ресурсам пакета A через пакет B.

Специальный пакет Wurst

По умолчанию, каждый пакет неявно импортирует специальный пакет Wurst из стандартной библиотеки. Это наиболее часто используемый набор пакетов. Если вы не хотите импортировать пакеты из стандартной библиотеки, вы можете отключить эту функцию путем специального импорта
import NoWurst

Область видимости

По умолчанию, ресурсы пакета закрыты и не экспортируются. Чтобы ресурсы пакета могли быть импортированы другими пакетами, они должны быть явно объявлены публичными, директивой public
package First
int i // Закрытый по умолчанию - виден только внутри своего пакета
public int j // Открытый — будет импортирован другим пакетом

package Second
import First

int k = i // Ошибка!
int m = j // Работает, так как j открытый

Блок инициализации

Пакет может (но не обязан) содержать один или несколько блоков инициализации. Блок инициализации может располагать в любом месте пакета - как до, так и после объявления переменных/функций/классов и пр. Следует ожидать, что если переменная будет объявлена ниже блока инициализации, то на момент выполнения кода в блоке инициализации, эта переменная не будет инициализирована.
Важно: Поскольку WC3 имеет лимит операций в одном потоке, вам следует избегать чрезвычайно большого количества действий внутри блока инициализации (например, инициализации больших баз данных), иначе их выполнение может резко прерваться без каких-либо предупреждений со стороны компилятора или игры. (Прим. Пер.: больше информации по этому вопросу вы сможете найти в статье "Лимит операций")

Порядок инициализации и initlater

Правила инициализации пакетов Wurst довольно просты:
  1. Инициализация внутри пакета происходит сверху вниз
  2. Процесс инициализации пакета объединяет в себе инициализацию всех глобальных переменных пакета (в том числе, статические атрибуты классов) и выполнение кода всех блоков инициализации
  3. Если пакет был импортирован с применением директивы initlater, он будет инициализирован после инициализации импортирующего пакета
package A
import initlater B
import public initlater C
import D
Пакет D будет инициализирован раньше импортирующего его пакета A. Пакеты B и C будут инициализированы после инициализации пакета A, вопреки общему порядку инициализации, это гарантировано директивой initlater. Данный прием позволит избежать проблем связанных с циклическим импортом.

Пакеты конфигураций

Глобальные переменные и функции пакета могут быть переопределены внутри специального пакета конфигураций.
Каждый пакет может иметь связанный с ним пакет конфигураций и каждый пакет конфигураций может сконфигурировать только 1 пакет. Отношение между пакетом и его пакетом конфигураций определяется правилом именования пакетов — имя пакета конфигураций получается из имени конфигурируемого пакета с постфиксом _config.
Переменная (функция), которая будет переопределена, должна быть объявлена с применением аннотации @configurable. Внутри же пакета конфигураций необходимо объявить переменную (функцию) с таким же именем, применив аннотацию @config. Понять это будет проще на примере:
package Example
@configurable int x = 5
package Example_config
@config int x = 42
Переменная x пакета Example была переопределена пакетом конфигураций Example_config.
С функциями это работает аналогично
package Example
@configurable public function math(int x, int y) returns int
    return x + y
package Example_config
@config public function math(int x, int y) returns int
    return x*y

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

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