Перейти на главную страничку сайта (список статей, файлы для скачивания)

ФОРУМ (здесь можно обсудить эту статью, а также саму программу AutoHotkey и проблемы её использования)

Проект перевода документации AutoHotkey: перечень переведённых статей и статей в работе.

Оригинал статьи в AutoHotkey.chm: "Functions [v1.0.31+]", в содержании - "Functions"

Ник переводчика: Gourmet.

Настоящее имя переводчика: Валентина Гаврикова, г.Москва.

Функции [v1.0.31+]

Содержание

Введение и простые примеры

Функция похожа на подпрограмму (Gosub), отличаясь от нее только способностью принимать параметры (входные данные) от вызывающего оператора. Кроме того, функция при желании может возвращать значения вызывающему оператору. Рассмотрим приведенный ниже пример простой функции, принимающей два числа и возвращающей их сумму:

Add(x, y)
{
	return x + y ; "return" ожидает выражение
}

Приведенный выше пример называется определением функции, так как создает функцию под названием "Add" (нечувствительно к регистру) и определяет, что для вызова этой функции необходимо задать ровно два параметра (x и y). Чтобы вызвать функцию, присвойте ее результат переменной с оператором :=, как показано в примере:

Var := Add(2, 3) ; Число 5 будет сохранено в Var.

Функцию можно также вызвать, не сохраняя возвращаемое значение:

Add(2, 3)

Однако в этом случае любое значение, возвращаемое функцией, отбрасывается. Поэтому, если исполнение функции не приводит к какому-нибудь другому результату помимо возврата значения, в вызове этой функции нет никакого смысла.

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

if InStr(MyVar, "fox")
	MsgBox Переменная MyVar содержит слово fox.

И, наконец, функции можно вызывать в параметрах любой команды (кроме параметров OutputVar и InputVar, таких, как в команде StringLen). Однако в параметрах, не поддерживающих выражения, обязательно нужно использовать префикс "%":

MsgBox % "Ответ: " . Add(3, 2)

Параметры

При определении функции ее параметры перечисляются в круглых скобках рядом с именем функции (между именем функции и открывающей скобкой не должно быть пробелов). Если функция не должна принимать никаких параметров, оставьте скобки пустыми. Например: GetCurrentTimestamp().

Для функции параметры по существу являются тем же самым, что и локальные переменные, кроме случаев, когда они определены как ByRef:

Swap(ByRef Left, ByRef Right)
{
	temp := Left
	Left := Right
	Right := temp
}

В примере, приведенном выше, в результате использования ByRef каждый параметр становится псевдонимом для переменной, переданной от вызывающего оператора. Другими словами, как сам параметр, так и переменная вызывающего оператора ссылаются на одно и то же содержимое памяти, что позволяет функции Swap изменять переменные вызывающего оператора, перемещая содержимое параметра Left в параметр Right и наоборот.

И напротив, если бы ByRef в этом примере не использовался, параметры Left и Right были бы копиями переменных вызывающего оператора, и функция Swap не имела бы должного эффекта.

Поскольку команда return может возвращать только одно значение, ByRef можно использовать для того, чтобы посылать дополнительные результаты обратно оператору, вызывающему функцию. Это достигается при передаче вызывающим оператором переменной (обычно пустой), в которой функция сохранит значение.

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

Опциональные параметры [v1.0.35+]

При определении функции один или несколько параметров можно пометить как опциональные. Для этого к параметру добавляется знак равенства и значение по умолчанию. В примере, приведенном ниже, параметр Z помечен как опциональный:

Add(X, Y, Z = 0)
{
	return X + Y + Z
}

Когда в примере вызывающий оператор передает функции три параметра, значение по умолчанию игнорируется. Однако, если передано только два параметра, параметру Z автоматически присваивается значение 0.

Нельзя поставить опциональные параметры в середину списка параметров. Другими словами, все параметры, расположенные справа от первого опционального параметра, также должны быть опциональными.

Значение параметра по умолчанию должно быть одним из следующих: true, false, буквальное целое число, буквальное число с плавающей запятой или буквальная пустая строка ("").

Локальные переменные

Все переменные, которые упомянуты или созданы внутри функции, являются локальными по умолчанию (кроме встроенных переменных, таких, как Clipboard, ErrorLevel или A_TimeIdle). Содержимое каждой локальной переменной могут видеть только команды, используемые внутри функции. Следовательно, локальная и глобальная переменные могут иметь одно имя, но разное содержание. И наконец, каждый раз при вызове функции локальная переменная первоначально не имеет значения.

Глобальные переменные: чтобы сослаться на существующую глобальную переменную внутри функции (или создать новую глобальную переменную), перед использованием объявите эту переменную глобальной. Например:

LogToFile(TextToLog)
{
	global LogFileName ; Эта глобальная переменная получила значение вне данной функции.
	FileAppend, %TextToLog%`n, %LogFileName%
}

Если функции необходимо создать или сослаться на большое количество глобальных переменных, можно объявить все переменные функции глобальными (кроме ее параметров). Для этого необходимо поместить в первой строке слово "global" или объявить в ней локальную переменную. Например:

SetDefaults()
{
	global ; Это слово можно опустить, если первая строка будет выглядеть следующим образом: "local MyVar".
	Var := 33 ; Присваивает глобальной переменной число 33, при необходимости создав эту переменную.
	local x, y, z
	;В этом режиме локальные переменные должны быть явно объявлены, иначе они будут считаться глобальными.
	...
}

Глобальный режим также можно использовать в функции для создания глобального массива, как например, цикл, присваивающий значения Array%A_Index%.

Статические переменные: чтобы сохранить значение переменной между вызовами, ее можно объявить статической. Например:

LogToFile(TextToLog)
{
	static LineCount
	LineCount += 1  ; Счетчик поддерживается локально (его значение сохраняется между вызовами).
	global LogFileName
	FileAppend, %LineCount%: %TextToLog%`n, %LogFileName%
}

Подразумевается, что статические переменные всегда локальны. Кроме того, единственный способ увидеть, что статическая переменная используется впервые - это проверить, имеет ли она значение.

Дополнительная информация о локальных и глобальных переменных:

Несколько переменных можно объявить в одной и той же строке, разделив их запятыми, как показано в примере:

global LogFileName, MaxRetries
static TotalAttempts, PrevResult

Поскольку слова local, global и static обрабатываются немедленно после запуска скрипта, их нельзя выполнить с помощью условного оператора. Другими словами, использование слов local, global или static внутри блока IF или ELSE вступает в силу безоговорочно. Кроме того, на сегодняшний день невозможно объявить динамическую переменную, как, например global Array%i%.

Внутри функции ссылка на динамическую переменную (напр.: Array%i%) всегда разрешается в локальную переменную, если переменная с таким именем существует. В противном случае используется глобальная переменная. Если не существует ни локальной, ни глобальной переменной, будет создана локальная переменная (если не действует глобальный режим).

Таким образом, функция может создать глобальный массив вручную (например, так: Array%i% := A_Index) только в глобальном режиме.

Для команд, создающих массивы (таких, как StringSplit), полученный в результате массив будет локальным, если не действует глобальный режим или если первый элемент массива объявлен как локальная переменная (сказанное также верно, если передан один из параметров функции, даже если этот параметр ByRef). И наоборот, если первый элемент был объявлен глобальным, будет создан глобальный массив. Первым элементом для команды StringSplit является ArrayName0. Для других создающих массивы команд, таких, как WinGet List, первым элементом является ArrayName (т.е. без числа).

Использование директивы #Include для распределение функций между множественными скриптами

Для загрузки функций из внешнего файла можно использовать директиву #Include (даже в начале скрипта).

Пояснения: когда скрипт в процессе исполнения встречает определение функции, он немедленно пропускает его и возобновляет исполнение со строки после закрывающей скобки. Следовательно, выполнение никогда не может начаться с подобной функции, а присутствие одной или нескольких функций на самом верху скрипта не влияет на секцию авто-выполнения.

Схема быстрой булевой оценки

Если операторы AND и OR используются внутри выражения, применяется схема быстрой оценки (вне зависимости от того, есть ли вызовы функции). При этой схеме не оцениваются части выражения, не влияющие на конечный результат. Рассмотрим пример, иллюстрирующий эту мысль:

if (ColorName <> "" AND not FindColor(ColorName))
	MsgBox %ColorName% не может быть найден.

В приведенном примере функция FindColor() никогда не будет вызвана, если переменная ColorName не имеет значений, так как левая часть выражения с оператором AND будет ложной, и, следовательно, его правая часть не сможет изменить конечный результат на истинно.

Очень важно понять, что подобное поведение приводит к тому, что если функция вызвана в правой части выражений с операторами AND или OR, любой побочный эффект, порожденный функцией, такой, как изменение содержимого глобальной переменной, возможно никогда не будет иметь место.

Также следует заметить, что быстрая оценка будет производиться иерархически по вложенным операторам AND и OR. Например, в следующем выражении, если ColorName не имеет значения, будет производиться только крайнее левое сравнение, так как в этом случае левой стороны достаточно, чтобы с уверенностью определить итоговый результат:

if (ColorName = "" OR FindColor(ColorName, Region1) OR FindColor(ColorName, Region2))
	break ; Искать нечего, или мы нашли соответствие.

Как показано в примере, приведенном выше, для увеличения производительности затратную (занимающую много времени) функцию, как правило, следует помещать в правую часть выражений с операторами AND или OR. Эту технику можно также использовать, чтобы помешать вызову функции, если один из параметров содержит неподходящее значение (напр., пустую строку).

Использование подпрограмм в функции

Хотя функция не может содержать определений других функций, она может содержать приватные подпрограммы. Как и в случае с другими подпрограммами, используйте команду Gosub для запуска функций и команду Return для возврата (при этом команда Return будет принадлежать команде Gosub, а не функции).

Если функция использует команду Gosub, чтобы перейти к общедоступной подпрограмме (той, что находится за пределами фигурных скобок функции), все переменные будут глобальными, а собственная локальная переменная функции будет недоступна, пока исполняется подпрограмма.

Хотя использование команды Goto как правило не одобряется, ее можно применить внутри функции, чтобы перейти на другую позицию внутри той же самой функции, что может помочь упростить большие функции, имеющие много точек возврата, каждая из которых перед возвратом должна сделать некоторую зачистку.

Хотя команда Goto, направленная вне функции, игнорируется, функция может перейти (Gosub) к внешней/общедоступной подпрограмме, после чего выполнить команду Goto оттуда.

Функция может содержать подпрограммы для таймеров (timers), меток перехода GUI, пунктов меню и других похожих функций. Это нужно, чтобы заключить подпрограммы в отдельный файл для использования с директивой #Include, что предохраняет их от использования вместе с секцией авто-выполнения скрипта. Однако если функция таких подпрограмм будет вызываться и обычным способом, а не просто служить в качестве контейнера для подпрограмм, то эти подпрограммы должны использовать только статические и глобальные переменные (не локальные). Причиной этого служит то, что поток подпрограммы, прерывающий поток вызова функции (или наоборот) сможет изменять значения локальных переменных, обнаруженных прерванным потоком. Кроме того, каждый раз, когда функция возвращается к своему вызывающему оператору, все локальные переменные функции очищаются от значений, чтобы освободить их память.

Общие замечания

Если поток выполнения, действующий внутри функции, достигает закрывающей скобки функции до того, как дойдет до команды Return, функция заканчивается и возвращает вызывающему оператору пустое значение (пустую строку). Пустое значение возвращается и в тех случаях, когда функция явно опускает параметры команды Return.

Если функция использует команду Exit для завершения текущего потока, оператор, вызывающий функцию, не получает никакого значения. Например, если Add() использует команду Exit, оператор Var := Add(2, 3) оставит переменную Var без изменений. То же самое происходит, если функция приводит к ошибке времени исполнения, такой, как например, запуск несуществующего файла (если параметр UseErrorLevel не действует).

Функция может изменить значение переменной ErrorLevel, чтобы возвратить дополнительное значение, более легкое для запоминания.

Чтобы вызвать функцию с одним или несколькими пустыми значениями (пустыми строками), используйте пустую пару кавычек, как показано в примере: FindColor(ColorName, "")

Поскольку вызов функции не начинает новый поток, любые изменения, сделанные функцией в настройках, таких, как SetKeyDelay и SetTitleMatchMode, вступят в силу и для оператора, вызывающего эту функцию.

Оператор, вызывающий функцию, может передать ей несуществующую переменную или элемент массива, что удобно, если функция ждет, что соответствующим параметром будет параметр ByRef. Например, вызов GetNextLine(BlankArray%i%) автоматически создаст переменную BlankArray%i% (какой она будет, локальной или глобальной, зависит от местоположения вызывающего оператора и от того, будет ли действовать глобальный режим.)

Команда ListVars может отражать локальные переменные вместе с их содержимым, что полезно при отладке скриптов.

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

Правила присваивания имен: возможно, вы увидите, что сложные функции более удобны для чтения и эксплуатации, если присвоить их специальным переменным отличительные префиксы. Например, если присвоить каждому параметру в списке параметров функции лидирующую "p" или "p_", этот тип параметров будет легче определить с первого взгляда, особенно, если в функции используется несколько десятков локальных переменных. Подобным образом, префикс "r" или "r_" можно использовать для параметров ByRef, а "s" или "s_" - для статических переменных.

Встроенные функции

Опциональные параметры в конце списка параметров встроенной функции можно совсем опустить. Например, функция WinExist("Untitled - Notepad") действительна, поскольку остальные три параметра этой функции будут считаться пустыми.

Встроенная функция будет замещена, если в скрипте задана собственная функция с тем же именем. Например, в скрипте может быть собственная функция WinExist(), которая будет вызвана вместо стандартной функции.

Внешние функции, постоянно хранящиеся в DLL-файлах, можно вызвать с помощью команды DllCall().

Все встроенные функции требуют версии 1.0.34 и выше, кроме функций WinActive и WinExist, которые требуют версии 1.0.31 и выше.


Часто используемые функции


FileExist(FilePattern): возвращает пустое значение (пустую строку), если FilePattern не существует. Иначе, возвращает строку атрибутов (подмножество "RASHNDOCT") первого подходящего файла или папки. Параметром FilePattern может быть точное имя файла или папки, или он может содержать групповой символ (* или ?). Поскольку пустая строка рассматривается как "ложь", возврат функции может всегда использоваться как квази-булево значение. Например, оператор if FileExist("C:\My File.txt") будет истинным, если файл существует, и ложным иначе. Подобным образом, оператор if InStr(FileExist("C:\My Folder"), "D") будет истинным, только если файл существует и является директорией. Если не указан абсолютный путь, то предполагается, что параметр FilePattern находится в переменной A_WorkingDir. Похожие команды: IfExist и FileGetAttrib.

GetKeyState(KeyName [, "P" or "T"]): в отличие от команды GetKeyState, которая возвращает D, когда клавиша нажата и U, когда она отпущена, данная функция возвращает истину (1), если клавиша нажата и ложь (0), если опущена. Если параметр KeyName недействителен, возвращается пустая строка. См. о других возвращаемых значениях и об инструкциях по применению в описании команды GetKeyState.

InStr(Haystack, Needle [, CaseSensitive?, StartingPos]): возвращает позицию первого вхождения строки Needle в строку Haystack. В отличие от команды StringGetPos, позиция 1 является первым символом, так как 0 - синоним "false" и является интуитивным индикатором "не найдено". Если параметр CaseSensitive опущен или ложен, поиск не чувствителен к регистру; иначе, регистр должен точно совпадать. Если параметр StartingPos опущен, то по умолчанию он равен 1 (начало строки Haystack). Иначе, задайте 2, чтобы начать со второго символа строки Haystack, 3 - с третьего, и т.д. Если параметр StartingPos больше, чем количество символов Haystack, возвращается 0. Если StartingPos равен 0, поиск проводится в обратном порядке (справа налево), с тем, чтобы найти соответствие, находящееся правее остальных. Вне зависимости от значения параметра StartingPos, возвращаемая позиция всегда соотносится с первым символом Haystack. Например, позиция строки "abc" в строке "123abc789" всегда 4. Похожие команды: IfInString и StringGetPos.

StrLen(String): возвращает длину String (строки). Если String является переменной, которой ранее было задано значение ClipboardAll, возвращается полный размер строки. Похожая команда: StringLen.

WinActive("WinTitle" [, "WinText", "ExcludeTitle", "ExcludeText"]): возвращает уникальный идентификатор активного окна, если оно соответствует заданным условиям. Если соответствия нет, функция возвращает 0. Так как все числа, не равные нулю, рассматриваются как "истина", оператор if WinActive("WinTitle") верен, если окно WinTitle активно. См. описание команды IfWinActive.

WinExist("WinTitle" [, "WinText", "ExcludeTitle", "ExcludeText"]): возвращает уникальный идентификатор первого совпадающего окна (0, если совпадения нет). Так как все числа, не равные нулю, рассматриваются как "истина", оператор if WinExist("WinTitle") верен, если окно WinTitle существует. См. описание команды IfWinExist.


Прочие функции


Asc(String): возвращает для первого символа в параметре String код ASCII (число в диапазоне от 1 до 255). Если String не имеет значения, возвращается 0.

Chr(Number): возвращает символ, соответствующий коду ASCII, заданному параметром Number. Если Number не принадлежит диапазону от 1 до 255 включительно, возвращается пустая строка. Часто используемые коды ASCII - 9 (табуляция), 10 (перевод строки), 13 (возврат каретки), 32 (пробел), 48-57 (0-9), 65-90 (A-Z) и 97-122 (a-z).

IsLabel(LabelName) [в версиях от 1.0.38 и выше]: возвращает число, не равное нулю, если параметр LabelName существует в скрипте в виде подпрограммы, горячей клавиши или строки автозамены (не включайте в параметр LabelName конечную запятую). Например, оператор if IsLabel(VarContainingLabelName) верен, если метка существует, и ложен иначе. Функция полезна для того, чтобы избежать ошибок времени исполнения при определении динамической метки в таких командах, как Gosub, Hotkey, Menu и Gui.

OnMessage(MsgNumber [, "FunctionName"]): см. описание команды OnMessage.

VarSetCapacity(UnquotedVarName [, RequestedCapacity]): увеличивает ёмкость переменной или освобождает её память. См. описание команды VarSetCapacity.


Общая математика


Примечание: обычно, если одним из входящих параметров является нечисловое значение, математические функции возвращают пустое значение (пустую строку).

Abs(Number): возвращает абсолютное значение параметра Number. Возвращаемое значение принадлежит тому же типу, что и Number (целое число или число с плавающей запятой).

Ceil(Number): возвращает параметр Number, округленный до ближайшего целого числа в большую строну (без суффикса .00). Например, Ceil(1.2) равно 2, а Ceil(-1.2) равно -1.

Exp(N): возвращает e (приблизительно 2.71828182845905), возведенную в степень N. Параметр N может быть отрицательным и содержать десятичную точку. Чтобы возвести в степень другие числа (не равные e), используйте оператор **.

Floor(Number): возвращает параметр Number , округленный до ближайшего целого числа в меньшую строну (без суффикса .00). Например, Floor(1.2) равно 1, а Floor(-1.2) равно -2.

Log(Number): возвращает логарифм (с основанием 10) параметра Number. Формат результата - число с плавающей запятой. Если параметр Number отрицательный, возвращается пустая строка.

Ln(Number): возвращает натуральный логарифм (с основанием e) параметра Number. Формат результата - число с плавающей запятой. Если параметр Number отрицательный, возвращается пустая строка.

Mod(Dividend, Divisor): возвращает остаток от деления Dividend на Divisor. Знак результата и знак первого параметра всегда совпадают. Например, как mod(5, 3), так и mod(5, -3) возвращают 2, однако mod(-5, 3) и mod(-5, -3) возвращают -2. Если какой-либо из входящих данных является числом с плавающей запятой, результатом также является число с плавающей запятой. Например, mod(5.0, 3) возвращает 2.0, а mod(5, 3.5) возвращает 1.5. Если второй параметр равен нулю, функция возвращает пустой результат (пустую строку).

Round(Number [, N]): если параметр N опущен или равен 0, параметр Number округляется до ближайшего целого числа. Если N - положительное число, Number округляется до N знаков после запятой. Если параметр N отрицательный, Number округляется до N разрядов слева от десятичной точки. Например, Round(345, -1) равно 350, а Round (345, -2) равно 300. В отличие от команды Transform Round, в случае, если параметр N опущен или меньше либо равен нулю, результат не имеет суффикса .000.

Sqrt(Number): возвращает квадратный корень от параметра Number. Формат результата - число с плавающей запятой. Если параметр Number отрицательный, функция возвращает пустой результат (пустую строку).


Тригонометрия


Sin(Number) | Cos(Number) | Tan(Number): возвращает тригонометрические синус/косинус/тангенс параметра Number. Number должен быть выражен в радианах.

ASin(Number): возвращает арксинус (число, синус которого равен параметру Number) в радианах. Если параметр Number меньше -1 или больше 1, функция возвращает пустой результат (пустую строку).

ACos(Number): возвращает арккосинус (число, косинус которого равен параметру Number) в радианах. Если параметр Number меньше -1 или больше 1, функция возвращает пустой результат (пустую строку).

ATan(Number): возвращает арктангенс (число, тангенс которого равен параметру Number) в радианах.

Перейти на главную страничку сайта (список статей, файлы для скачивания)

© 2007 http://www.script-coding.com При любом использовании материалов сайта обязательна ссылка на него как на источник информации, а также сохранение целостности и авторства материалов.