Добавлен , не публикуется

vJass

Содержание:

Содержание главы:

Лирика

Ранее мы рассмотрели такую вещь как область - специальную конструкцию, преследующую цели:
  • Визуально выделить некоторый глобальный блок кода
  • Ограничить доступ к некоторым конструкциям, посредством определения пространства имен, используя ключевое слово public
  • Полностью закрыть доступ к некоторым конструкциям, посредством ключевого слова private
  • Используя функцию инициализации, превратить область в самостоятельный, независимый модуль
Таким образом, мы способны реализовать принципы модульности и инкапсуляции в языке Jass.
Теперь давайте представим ситуацию - мы написали некоторый набор полезных, допустим, математических функций и планируем использовать этот набор функций во всей своей карте. Для удобства, используем возможности областей, чтобы объединить весь этот набор функций в некоторое пространство имен, назовем эту область Math. Все внешние функции этой области мы помечаем ключевым словом public, дабы иметь к ним доступ исключительно через префикс Math_ избегая возможного конфликта имен с остальным кодом карты. Что теперь мы должны сделать?
Нам известно, что прежде использования какой-либо функции, мы должны ее объявить. То есть, вызываемая функция, должна располагаться по коду выше места ее вызова. Соответственно, наша область Math должна располагаться по коду выше всех мест вызова содержащихся в ней функций.
Очевидно, нам необходимо переместить нашу область в CustomScript раздел карты, поскольку он располагается выше кода всякой секции триггера. Однако, если мы используем множество подобных наработок, наш CustomScript превратится в большую кучу абсолютно несвязного кода. Что еще хуже, некоторые наборы утилит, подобно нашему Math, могут быть зависимы от других подобных наборов и теперь мы вынуждены предусматривать их расположение друг относительно друга.
Итак, мы приобретаем приличное количество нудной и раздражающей работы.
Для простоты решения поставленных выше задач, не помешал бы некоторый контроль над расположением кода внутри карты и в этом месте vJass вводит в свой синтаксис библиотеки.
Конструкция библиотек схожа, если не сказать идентична, областям. Библиотеки так же определяют некоторый блок кода, который может быть выделен как просто визуально, так и стать самостоятельным модулем. Однако, важнейшее отличие библиотек - их код автоматически переносится парсером на самый верх кода карты, сразу после секции глобальных переменных и нативных функций, что даже выше CustomScript раздела карты. Таким образом, вы можете объявить библиотеку в любом угодном вам месте, будь то CustomScript или секция триггера и быть уверенными, что функции этой библиотеки будут доступны откуда угодно.

Объявление

Как говорилось ранее, библиотеки во многом схожи с областями, посему их конструкцию будет проще понять на примере:
код
library NAME initializer Init
	globals
		public real X
		// Прочие глобальные переменные...
	endglobals
	
	// Прочий код библиотеки...
	
	private function Init takes nothing returns nohing
		// Код функции инициализации...
	endfunction
endlibrary
Вы уже можете сделать некоторые выводы из кода представленного выше, тем не менее, вкратце стоит описать их основные возможности, в том числе, чтобы не повторять текст предыдущего параграфа:
  • Библиотеки могут содержать публичные конструкции, объявленные с ключевым словом public. Доступ к публичным членам извне объемлющей библиотеки организуется посредством добавления префикса в виде имени библиотеки и символа подчеркивания. Для доступа к членам внутри объемлющей библиотеки префикс не обязателен.
  • Библиотеки могут содержать приватные конструкции, объявленные с ключевым словом private. Доступ к приватным членам извне объемлющей библиотеки закрыт.
  • Внутри библиотек доступны строковые константы SCOPE_PREFIX и SCOPE_PRIVATE, содержащие префиксы для имен публичных и приватных членов соответственно объемлющей библиотеки.
  • Библиотека может (но не обязана) иметь функцию инициализации, имя которой указывается после ключевого слова initializer, следующим сразу за именем библиотеки.
  • Внутри библиотеки можно объявлять области.
  • Внутри библиотек нельзя объявлять другие библиотеки
Как вы наверно поняли, все выше перечисленные возможности идентичны возможностям областей.
Помните главное - весь код библиотеки, независимо от места ее объявления, будет перенесен парсером на самый верх кода карты, выше CustomScript раздела, обеспечив доступ к функциям библиотек из любой секции редактора триггеров.

Зависимости

Представим ситуацию - мы объявили два набора полезных функций, которые будут использованы во всей нашей карте. Очевидно, будет рационально инкапсулировать эти наборы в библиотеки, назовем их библиотекой A и библиотекой B. Теперь мы можем быть уверены в доступности этих двух наборов, откуда угодно из кода карты. Однако оказывается, что для работы функций библиотеки A, требуются функции библиотеки B. Учитывая, что парсер самостоятельно переносит код библиотек на верх кода карты, как мы можем быть уверенны, что конечный порядок наших библиотек, после обработки, будет удовлетворять нуждам? Для этого указываются зависимости библиотек.
Для определения зависимостей используется ключевое слово requires, за которым следует имя требуемой библиотеки
код
library A requires B
	// Код библиотеки A...
endlibrary

library B
	// Код библиотеки B...
endlibrary
Теперь, независимо от порядка объявления, мы можем быть уверенны, что парсер учтет зависимость библиотек и расположит код библиотеки B выше кода библиотеки A.
Если библиотека имеет сразу несколько зависимостей, они просто указываются через запятую
код
library A requires B, C, D
	// Код библиотеки A...
endlibrary
По абсолютно бессмысленным причинам, вы можете указывать зависимости посредством любого из 3х ключевых слов - requires, uses, needs.
Функция инициализации в данном случае, указывается как и прежде, а зависимости сразу после нее
код
library A initializer Init uses B, C, D
	private function Init takes nothing returns nothing
		// ...
	endfunction
endlibrary
В этом случае необходимо заметить - функция инициализации востребованной библиотеки выполняется прежде функции инициализации основной библиотеки. То есть, в примере выше, функция инициализации библиотеки B будет выполнена раньше функции инициализации библиотеки A.

Опциональная зависимость

Зависимость от библиотеки может быть указана как опциональная, посредством ключевого слова optional перед именем востребованной библиотеки.
Если мы попытаемся указать зависимость от библиотеки, которой нет в карте, компилятор выдаст ошибку. Однако, если востребованная библиотека указана как опциональная, то компилятор, в случае отсутствия таковой в коде карты, ее просто проигнорирует.
код
library A needs optional B
	// ...
endlibrary
Данная конструкция используется в сочетании со static if, о чем мы поговорим в следующем параграфе.

Константа LIBRARY_Name

В дополнение к предыдущему пункту, следует упомянуть о существовании специальной константы.
Каждый раз, когда парсер натыкается на объявление новой библиотеки, он генерирует логическую константу LIBRARY_Name, где Name - имя библиотеки. Таким образом можно проверить наличие той или иной библиотеки в карте
код
library A initializer Init
	// ...
endlibrary

function AnyFunction takes nothing returns nothing
	if LIBRARY_A then
		call BJDebugMsg("Library A exist!")
	endif
endfunction
Как и в случае с опциональной зависимостью, эта возможность используется в сочетании со static if, о чем будет рассказано в следующем параграфе.

library_once

Для объявления библиотеки, вы можете использовать ключевое слово library_once.
Если вы объявите две библиотеки с одним и тем же именем, компилятор выдаст ошибку. Если библиотека была объявлена посредством library_once, библиотека с тем же именем будет просто проигнорирована.
код
library A
	// ...
endlibrary

library_once A // Повторное объявление, библиотека будет проигнорирована
	// ...
endlibrary
Может оказаться полезно в сочетании с макросами.

`
ОЖИДАНИЕ РЕКЛАМЫ...