함수

목차

소개와 간단한 예제

함수는 서브루틴 (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가 들어 있습니다.

마지막으로, 함수는 다른 명령어의 매개변수에서 호출할 수도 있습니다 (StringLen의 매개변수와 같이 OutputVar와 InputVar 같은 매개변수는 예외입니다). 그렇지만, 표현식을 지원하지 않는 매개변수는 다음 예제와 같이 반드시 "% " 를 접두기호로 사용해야 합니다:

MsgBox % "정답은 다음과 같습니다: " . Add(3, 2)

"% " 접두기호는 또 근본적으로 표현식을 지원하는 매개변수에도 허용됩니다. 그러나 그냥 무시됩니다.

매개변수

함수가 정의될 때, 그의 매개변수는 함수 이름 옆 괄호 안에 나열됩니다 (함수와 여는 괄호 사이에 공간이 있으면 안됩니다). 함수가 매개변수를 받지 않으면, 괄호를 빈 채로 둡니다: GetCurrentTimestamp().

ByRef 매개변수: 함수의 관점에서, 매개변수는 본질적으로 지역 변수와 똑같습니다. 그러나 다음 예제와 같이 ByRef로 정의된다면 다릅니다:

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

위의 예제에서, ByRef를 사용하면 각 매개변수들이 호출자로부터 들어오는 변수에 대하여 별명이 됩니다. 다른 말로, 매개변수와 호출자의 변수는 모두 메모리의 같은 내용을 가리킵니다. 이 때문에 Swap 함수는 호출자의 변수를 변경할 수 있습니다. Left의 내용을 Right으로 그리고 그 반대로 이동시킬 수 있습니다.

대조적으로, ByRef가 위의 예제에서 사용되지 않았다면, LeftRight는 호출자 변수의 사본이 되어야 합니다. 그래서 Swap 함수는 외부적으로 아무 효과가 없을 것입니다.

return은 함수의 호출자에게 오직 하나의 값만 다시 돌려줄 수 있기 때문에, ByRef를 사용하면 추가 결과를 더 돌려줄 수 있습니다. 호출자에게 (보통 빈) 변수를 건네게 하고 거기에 함수가 값을 저장하면 됩니다.

방대한 문자열을 함수에 건넬 때, ByRef는 수행성능을 향상시키고 메모리를 그대로 유지합니다. 문자열의 사본을 만들 필요가 없기 때문입니다. 비슷하게, ByRef를 사용하여 긴 문자열을 다시 호출자에게 보내면 Return HugeString와 같이 하는 것에 비해 보통 수행성능이 더 향상됩니다.

[AHK_L 60+]: 변경가능한 변수 말고 어떤 것이 ByRef 매개변수에 건네지면, 함수는 마치 키워드 "ByRef"가 없는 것처럼 행위합니다. 예를 들어, Swap(A_Index, i)A_Index의 값을 i에 저장하지만, Left에 할당된 값은 Swap 함수가 반환되는 순간 폐기됩니다.

[v1.1.01+]: IsByRef() 함수를 사용하면 호출자가 주어진 ByRef 매개변수에 대하여 변수를 공급했는지 알 수 있습니다.

알려진 한계:

선택적 매개변수

함수를 정의할 때, 하나 이상의 매개변수에 선택적 표식을 할 수 있습니다. 먼저 등호 사인을 두고 (또는 v1.1.09+에서는 :=) 다음에 기본값을 두면 됩니다. 다음 함수는 Z 매개변수에 선택적 표식이 붙어 있습니다:

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

v1.1.09 버전부터 =:= 둘 다 지원합니다. 표현식 할당과의 일관성과 미래 버전의 오토핫키와의 호환성을 위하여 후자를 권장합니다.

호출자가 세 개의 매개변수를 위의 함수에 건네면, Z의 기본 값은 무시됩니다. 그러나 호출자가 오직 두 개의 매개변수만 건네면, Z는 자동으로 기본값 0을 받습니다.

선택적 매개변수를 리스트 한 가운데에 따로 배치하는 것은 불가능합니다. 다른 말로 하면, 첫 번째 선택적 매개변수의 오른쪽에 나오는 모든 매개변수도 역시 선택적으로 표식이 붙어야 합니다. [AHK_L 31+]: 선택적 매개변수는 매개변수 리스트의 중앙에서는 생략할 수 있습니다. 아래와 같이 함수를 호출합니다. 동적인 함수 호출과 메쏘드 호출은 v1.1.12+이상이 필요합니다.

Func(1,, 3)
Func(X, Y:=2, Z:=0) {  ; 이 경우 Z는여전히 선택적이어야 함에 유의합니다.
    MsgBox %X%, %Y%, %Z%
}

v1.0.46.13+에서, ByRef 매개변수도 기본값을 지원합니다; 예를 들어: Func(ByRef p1 = ""). 호출자가 그런 매개변수를 빼먹을 때마다, 함수는 지역 변수를 만들어 기본 값을 담습니다; 다른 말로, 함수는 마치 키워드 "ByRef"가 존재하지 않는 것처럼 행위합니다.

매개변수의 기본 값은 다음 중 하나가 되어야 합니다: true, false, 문자 그대로의 정수, 문자 그대로의 부동 소수점 수, 또는 "fox" 또는 ""와 같이 인용부호처리되어 문자 그대로의 문자열. (그러나 1.0.46.13+이전 버전의 문자열은 오직 ""만 지원합니다).

호출자에게 값 돌려주기

소개에 기술한 바와 같이, 함수는 선택적으로 값을 호출자에게 돌려줄 수 있습니다.

Test := returnTest()
MsgBox % Test

returnTest() {
  return 123
}

함수로부터 결과를 더 많이 돌려주고 싶다면, ByRef를 사용할 수 있습니다:

returnByRef(A,B,C)
MsgBox % A "," B "," C

returnByRef(ByRef val1, ByRef val2, ByRef val3)
{
  val1 := "A"
  val2 := 100
  val3 := 1.1
  return
}

[v1.0.97+]: 객체배열을 사용하면 여러 값들 심지어 이름 붙은 값들도 돌려줄 수 있습니다:

Test1 := returnArray1()
MsgBox % Test1[1] "," Test1[2]

Test2 := returnArray2()
MsgBox % Test2[1] "," Test2[2]

Test3 := returnObject()
MsgBox % Test3.id "," Test3.val

returnArray1() {
  Test := [123,"ABC"]
  return Test
}

returnArray2() {
  x := 456
  y := "EFG"
  return [x, y]
}

returnObject() {
  Test := {id: 789, val: "HIJ"}
  return Test
}

가변 함수 [AHK_L 60+]

함수를 정의할 때, 별표를 마지막 매개변수 뒤에 쓰면 그 함수를 가변함수로 만들 수 있습니다. 가변 개수의 매개변수를 받을 수 있습니다:

Join(sep, params*) {
    for index,param in params
        str .= param . sep
    return SubStr(str, 1, -StrLen(sep))
}
MsgBox % Join("`n", "one", "two", "three")

가변 함수를 호출할 때, 넘치는 매개변수는 함수의 마지막 매개변수에 저장되어 있는 객체를 통하여 접근할 수 있습니다. 넘친 첫 번째 매개변수는 params[1]에 있고, 두 번째는 params[2]에 등등에 있습니다. 다른 표준 객체처럼params.MaxIndex()를 사용하면 숫치상 가장 높은 인덱스를 알 수 있습니다 (이 경우 매개변수의 개수입니다). 그렇지만, 매개변수가 없다면, MaxIndex는 빈 문자열을 돌려줍니다.

주의:

가변 함수 호출

가변 함수가 가변 개수의 매개변수를 받아들일 수 있는 반면, 매개변수 배열을 어떤 함수에도 건넬 수 있습니다. 같은 구문을 함수-호출에 적용하면 됩니다:

substrings := ["one", "two", "three"]
MsgBox % Join("`n", substrings*)

주의:

알려진 한계:

지역 변수와 전역 변수

지역 변수

함수 안에서 만들어지고 접근되는 모든 변수들은 기본적으로 지역적입니다 (슈퍼-전역 변수 그리고 Clipboard, ErrorLevel, A_TimeIdle와 같은 내장 변수는 제외합니다). 각 지역 변수의 내용은 함수 안에 든 줄에서만 보입니다. 결과적으로, 지역 변수는 전역 변수와 이름이 같을 수 있습니다. 그리고 서로 다른 내용을 가질 수 있습니다. 마지막으로, 모든 지역 변수는 함수가 호출될 때마다 빈 채로 시작합니다.

전역 변수

함수 안에서 기존의 전역 변수를 참조하려면 (또는 새로 만들려면), 변수를 global로 선언한 다음 사용합니다. 예를 들어:

LogToFile(TextToLog)
{
    global LogFileName  ; 이 전역 변수는 이 함수 바깥 어딘가에 미리 값이 주어져 있습니다.
    FileAppend, %TextToLog%`n, %LogFileName%
}

전역-간주 모드: 함수가 방대한 개수의 전역 변수를 만들거나 접근할 필요가 있다면, 그의 모든 변수를 전역적으로 간주하도록 정의할 수 있습니다 (매개변수는 제외). 첫 줄을 단어 "global"로 만들거나 지역 변수의 선언으로 만들면 됩니다. 예를 들어:

SetDefaults()
{
    global  ; 함수의 첫 줄이 "local MyVar"와 같은 것으로 시작하면 이 단어는 생략해도 됩니다.
    MyGlobal := 33  ; 33을 전역 변수에 할당합니다. 필요하면 먼저 변수를 만듭니다.
    local x, y:=0, z  ; 지역 변수는 이 모드로 선언해야 합니다. 그렇지 않으면 전역적으로 간주됩니다.
}

전역-간주 모드를 함수에 사용하면 예를 들어 값을 Array%A_Index%에 할당하는 회돌이와 같이 전역 배열을 만들 수 있습니다.

슈퍼-전역 변수 [v1.1.05+]: 전역 선언이 함수 밖에 나타나면, 기본으로 모든 함수에 영향을 미칩니다. 그래서 각 함수마다 해당 변수를 다시 선언할 필요가 없습니다. 그렇지만, 함수 매개변수나 지역 변수에 같은 이름이 선언되어 있다면, 전역 변수보다 우선 순위가 놓습니다. class 키워드로 만든 변수도 수퍼-전역 변수입니다.

정적 변수

정적 변수는 언제나 묵시적으로 지역적이지만, 지연 변수와는 다른 점이 있습니다. 호출 사이에 값을 기억합니다. 예를 들어:

LogToFile(TextToLog)
{
    static LoggedLines = 0
    LoggedLines += 1  ; 완전히 지역적으로 유지관리합니다 (그의 값은 호출 사이에 기억됩니다).
    global LogFileName
    FileAppend, %LoggedLines%: %TextToLog%`n, %LogFileName%
}

정적 초기화자: 1.0.46 이전 버전에서, 모든 정적 변수는 빈 채로 시작했습니다; 그래서 처음으로 사용되는 변수인지 탐지하는 유일한 방법은 그것이 비어있는지 점검하는 것이었습니다. v1.0.46+에서, 정적 변수는 "" 말고 다른 것으로 초기화할 수 있습니다. 먼저 :=이나 =를 두고 바로 이어 다음 중 하나가 오면 됩니다: true, false, 기호 그대로의 숫자, 기호 그대로의 부동 소수점 수, 또는 "fox"과 같이 기호 그대로/ 인용부호 처리된 문자열. 예를 들면: static X:=0, Y:="fox". 각 정적 변수는 (스크립트가 실행을 시작하기 전에) 오직 한 번만 초기화됩니다.

[AHK_L 58+]: Static var := expression을 지원합니다. 그런 모든 표현식은 나타나는 순서대로 스크립트의 자동-실행 섹션 바로 앞에서 평가됩니다.

정적-간주 모드 [v1.0.48+]: 함수는 그의 모든 변수가 정적이라고 간주하도록 정의할 수 있습니다 (그의 매개변수는 제외). 첫 줄을 "static"이라는 단어로 만들면 됩니다. 예를 들어:

GetFromStaticArray(WhichItemNumber)
{
    static
    static FirstCallToUs := true  ; 정적 선언의 초기화자는 여전히 (기동시에) 한 번만 실행됩니다.
    if FirstCallToUs  ; 첫 번째 호출 동안 정적 배열을 만듭니다. 그러나 그 다음 호출에는 만들지 않습니다.
    {
        FirstCallToUs := false
        Loop 10
            StaticArray%A_Index% := "Value #" . A_Index
    }
    return StaticArray%WhichItemNumber%
}

정적-간주 모드에서, 정적이면 안되는 변수는 반드시 local 또는 global로 선언해야 합니다.

지역 변수와 전역 변수에 관하여 더 자세히

많은 변수들을 한 줄에 선언할 수 있습니다. 다음 예제와 같이 쉼표로 가르면 됩니다:

global LogFileName, MaxRetries := 5
static TotalAttempts = 0, PrevResult

v1.0.46+에서, 전역 변수나 지역 변수는 선언과 동시에 같은 줄에서 초기화할 수 있습니다. :=이나 = 다음에 표현식을 두면 됩니다 (= 연산자는 선언에서 :=와 똑같이 행위합니다). 정적 초기화자와 다르게, 지역 변수와 전역 변수의 초기화자는 함수가 호출될 때마다 매번 실행됩니다. 그러나 오직 실행 흐름이 실제로 거기에 다다를 때에만 초기화합니다. 다른 말로, local x = 0과 같은 줄은 다음과 같이 두 개의 서술문으로 작성한 것과 효과가 같습니다: local x 다음에 x = 0.

local, global, 그리고 static같은 단어는 스크립트가 기동하자 마자 즉시 처리되기 때문에, 변수는 IF 서술문을 수단으로 하여 조건적으로 선언할 수 없습니다. 다른 말로 하면, IF 또는 ELSE 블록안에서 선언하면 해당 선언과 그 함수의 닫는 괄호 사이에 있는 모든 줄들에 예상치 못한 효과를 미칩니다. 또 주목할 것은 global Array%i%와 같이 동적으로 변수를 선언하는 것은 현재 가능하지 않다는 것입니다.

(StringSplit 같은) 의사-배열을 생성하는 명령어에 대하여, 전역-간주 모드가 영향이 없거나 또는 의사-배열의 첫 번째 원소가 지역 변수로 선언되어 있다면, 결과 의사-배열의 각 변수는 지역 변수입니다. (그 함수의 매개변수 중 하나가 건네질지라도 마찬가지입니다 -- 그 매개변수가 ByRef일지라도 -- 왜냐하면 매개변수는 지역 변수와 비슷하기 때문입니다). 역으로, 첫 원소가 global로 선언되었다면, 전역 배열이 생성됩니다. 그렇지만, 아래의 흔한 혼란의 근원이 이 경우에도 적용되니다. StringSplit의 첫 원소는 ArrayName0입니다. WinGet List와 같이 다른 배열-생성 명령어에 대하여, 첫 번째 원소는 ArrayName입니다 (즉, 숫자가 없습니다).

함수 안에서, Array%i%와 같은 동적 변수 참조는 해당 이름의 변수가 존재하지 않는 한, 언제나 지역 변수로 결정됩니다. 만약 존재하면 전역 변수가 사용됩니다. 아예 존재하지 않으면 새로 생성될 필요가 있습니다. 지역 변수로 생성됩니다. 단, 전역-간주 모드가 켜 있다면 전역 변수로 생성됩니다. 결과적으로, 함수는 (Array%i% := A_Index과 같은 수단을 사용하여) 수동으로 전역 배열을 만들 수 있습니다. 물론 전역-간주 함수로 선언되어 있어야 합니다.

흔한 혼란의 근원: 변수를 동적으로 참조했는데 존재하지 않으면 스크립트가 기동하는 순간 그 변수가 생성됩니다. 예를 들어, 함수 밖에서 사용될 때, MsgBox %Array1%는 스크립트가 기동하는 순간 Array1을 전역변수로 생성합니다. 반대로, 함수 안에서 사용될 때, MsgBox %Array1%는 스크립트가 기동하는 순간 (전역-간주 모드가 아닌 한), Array와 Array0이 전역 변수로 선언되어 있다고 할지라도, Array1을 지역 변수중 하나로 생성합니다.

동적으로 함수 호출하기

v1.0.47.06+에서, 함수는 (내장 함수도 역시) 퍼센트 사인을 통하여 동적으로 호출할 수 있습니다. 예를 들어, %Var%(x, "fox")는 이름이 Var 안에 들어 있는 함수를 호출합니다. 비슷하게, Func%A_Index%()는 A_Index의 현재 값에 따라서 Func1() 또는 Func2(), 등등을 호출합니다.

v1.1.07.00+에서, %Var%()Var는 함수 이름, 함수 참조 또는 함수를 흉내낸 객체를 담을 수 있습니다. 해당 함수가 존재하지 않으면, 기본 베이스 객체의 __Call 메타-함수가 대신에 요청됩니다.

아래의 이유 중 하나 때문에 함수를 호출할 수 없다면, 그 호출을 담고 있는 표현식의 평가가 조용히 그리고 너무 빨리 끝나므로, 일관성 없는 결과를 도출할 수 있습니다:

마지막으로, 함수를 동적으로 호출하면 정상 호출보다 약간 더 느립니다. 왜냐하면 정상 호출은 스크립트가 실행을 하기 전에 결정(검색 완료)되기 때문입니다.

단축-회로 불리언 평가

AND, OR, 그리고 삼진 연산자표현식 안에 사용될 때, 단축 회로 평가로 수행성을 개선합니다 (함수 호출이 존재하는가 여부에 상관없이). 단축 회로 평가는 최종 결과에 영향을 미칠 수 없는 부분을 평가하지 않습니다. 개념을 보여주기 위해, 다음 예제를 연구해 보겠습니다:

if (ColorName <> "" AND not FindColor(ColorName))
    MsgBox %ColorName%을 발견할 수 없습니다.

위의 예제에서, FindColor() 함수는 ColorName 변수가 비어있지 않는 한, 절대 호출되지 않습니다. 이 때문에 AND의 왼쪽이 false가 되고, 그의 오른쪽 만으로는 true라는 최종 결과를 생산할 가능성이 전혀 없기 때문입니다.

이 행위 때문에, 그 함수가 ANDOR의 오른쪽에 호출되더라도, 함수가 생산하는 부작용이 (전역 변수의 내용을 변경하는 것과 같은) 절대로 일어나지 않을 것이라는 사실을 깨닫는 것이 중요합니다.

또 주목할 것은 단축-회로 평가가 내포된 ANDOR에 단계적으로 적용된다는 것입니다. 예를 들어, 다음 표현식에서, ColorName이 비어 있으면 오직 왼쪽의 평가만 일어납니다. 왜냐하면 왼쪽 만으로 최종 정답을 확실하게 결정하기에 충분하기 때문입니다:

if (ColorName = "" OR FindColor(ColorName, Region1) OR FindColor(ColorName, Region2))
    break   ; 더 이상 검색 것이 없습니다. 일치한 것이 없습니다.

위의 예제에서 보여주는 바와 같이, 비싼 (시간이-드는) 함수라면 일반적으로 ANDOR의 오른쪽에서 호출해야 수행성능이 개선됩니다. 이 테크닉을 사용하면 또 그의 매개변수 중 하나에 부적절한 값이, 예를 들어 빈 문자열이 건네질 때, 함수가 호출되지 못하도록 만들 수 있습니다.

v1.0.46+에서, 삼진 조건 연산자 (?:)도 단축 평가를 합니다. 필요 없는 분기는 평가하지 않습니다.

함수 안에서 서브루틴 사용하기

함수에 다른 함수의 정의는 담을 수 없지만, 서브루틴은 담을 수 있습니다. 다른 서브루틴과 마찬가지로 Gosub로 기동하고 Return으로 반환됩니다 (이 경우 Return은 Gosub에 속하지 함수에 속하지 않습니다).

알려진 한계: 현재, 각 서브루틴의 이름(라벨)은 전체 스크립트 안에서 유일하게 식별할 수 있어야 합니다. 프로그램은 라벨이 중복되어 있으면 기동할 때 여러분에게 고지할 것입니다.

함수가 Gosub를 사용해 (함수의 괄호 밖에 존재하는) 공개 서브루틴으로 점프해 가면, 바깥의 모든 변수는 전역 변수이고 서브루틴이 돌아올 때까지 함수 자신의 지역 변수에는 접근할 수 없습니다. 그렇지만, A_ThisFunc는 여전히 함수의 이름을 담고 있을 것입니다.

Goto로는 함수 안에서 밖으로 점프해 갈 수 없지만, 함수는 외부/공개 서브루틴으로 Gosub할 수 있으며 거기부터 Goto를 사용하면 됩니다.

Goto의 사용은 일반적으로 권장하지 않지만, 함수 안에서 또다른 위치로 점프하는데 사용할 수 있습니다. 이렇게 하면 복잡한 함수를 간략하게 만드는 데 도움이 될 수 있습니다. 반환 지점이 수 없이 많고, 그 모두가 돌아오기 전에 깨끗하게 청소해야 할 경우 유용합니다.

함수는 외부적으로-호출되는 서브루틴을 담을 수 있습니다. 예를 들어 타이머, GUI g-labels, 그리고 메뉴 항목이 그것입니다. 일반적으로 별도의 파일에 싸 넣고 #Include와 함께 사용합니다. 이렇게 하면 스크립트의 자동-실행 섹션 때문에 서로 간섭하는 일을 막을 수 있습니다. 그렇지만, 다음 한계가 적용됩니다:

Return, Exit, 그리고 총평

다음 실행 흐름이 함수 안에서 Return을 만나기 전에 먼저 닫는 괄호에 도달하면, 그 함수는 끝나고 빈 값을 호출자에게 돌려줍니다 (빈 문자열). 빈 값은 또 함수가 명시적으로 Return의 매개변수를 생략할 때에도 반환됩니다.

함수가 Exit 명령어를 사용하여 현재 쓰레드를 종료하면, 그의 호출자는 반환 값을 전혀 받지 못합니다. 예를 들어, 다음 서술문 Var := Add(2, 3)는 가Add() 종료하면 Var를 그대로 둘 것입니다. 함수가 실행시간 에러를 일으켜도 같은 일이 일어납니다. 예를 들어 (UseErrorLevel가 켜져 있지 않을 때) 존재하지 않는 파일을 실행하면 같은 일이 일어납니다.

함수는 기억하기 쉬운 값을 추가로 건네기 위한 목적으로 ErrorLevel의 값을 변경할 수 있습니다.

함수를 하나 이상이 빈 값으로 호출하려면 (빈 문자열), 다음 예제와 같이 빈 따옴표 쌍을 사용합니다: FindColor(ColorName, "").

함수를 호출하면 새로운 쓰레드가 시작하므로, 함수가 SendModeSetTitleMatchMode와 같은 설정에 가한 변경은 모두 그의 호출자에게도 영향을 미칠 것입니다.

함수의 호출자는 거기에 존재하지 않은 값 또는 배열을 건넬 수 있습니다. 함수가 상응하는 매개변수를 ByRef라고 기대할 경우에 유용합니다. 예를 들어, GetNextLine(BlankArray%i%)를 호출하면 자동으로 BlankArray%i% 변수가 생성됩니다 (호출자가 함수 안에 있는가 그리고 그 함수에 전역-간주 모드가 켜져 있는가에 따라 지역 변수 또는 전역 변수로 생성됩니다).

함수 안에서 사용될 때, ListVars는 함수의 지역 변수들을 그의 내용과 함께 보여줍니다. 이는 스크립트를 디버깅할 때 도움이 됩니다.

스타일과 이름짓기 관례

복잡한 함수는 특별한 변수에 구별되는 접두사를 부여하면 더 읽기 쉽고 관리하기 좋다는 사실을 눈치채셨을 것입니다. 예를 들어, 함수의 매개변수 리스트에서 각 매개변수의 이름을 앞에 "p" 또는 "p_"를 두어 지으면 한 눈에 그의 특수한 본성을 쉽게 구별할 수 있습니다. 특히 함수에 수 십개의 지역 변수가 들어 있는데 전부 주의를 기울여 신경을 써야할 때 유용합니다. 비슷하게, 접두사 "r"이나 "r_"은 ByRef 매개변수에 사용하면 좋고, "s"나 "s_"는 정적 변수에 사용할 수 있습니다.

One True Brace (OTB) 스타일을 선택적으로 함수를 정의하는 데 사용할 수 있습니다. 예를 들어:

Add(x, y) {
    return x + y
}

#Include를 사용하여 여러 스크립트 사이에 함수 공유하기

#Include 지시어를 사용하면 (스크립트의 상단에도 가능) 함수를 외부 파일로부터 적재할 수 있습니다.

설명: 스크립트의 실행 흐름이 함수 정의를 만다면, (순간적으로) 그것을 건너 뛰고 함수의 닫는 괄호 다음 줄부터 실행을 재개합니다. 결과적으로 실행은 위쪽에 있는 함수로 들어갈 수 없으며, 스크립트 최상단에 하나 이상의 함수가 존재하더라도 자동-실행 섹션에 영향을 미치지 않습니다.

함수 라이브러리: 표준 라이브러리와 사용자 라이브러리 [v1.0.47+]

스크립트는 외부 파일에 있는 함수를 호출할 수 있습니다. #Include를 사용할 필요가 없습니다. 그러려면 함수와 같은 이름의 파일이 다음 라이브러리 디렉토리 중 하나에 존재해야 합니다:

%A_ScriptDir%\Lib\  ; 지역 라이브러리 - 필수 AHK_L 42+.
%A_MyDocuments%\AutoHotkey\Lib\  ; 사용자 라이브러리.
path-to-the-currently-running-AutoHotkey.exe\Lib\  ; 표준 라이브러리.

예를 들어, 스크립트가 존재하지 않는 함수 MyFunc()를 호출하면, 프로그램은 사용자 라이브러리에서 "MyFunc.ahk"라른 이름의 파일을 찾습니다. 발견하지 못하면, 표준 라이브러리에서 찾습니다. 여전히 발견하지 못하면 그리고 함수의 이름에 밑줄이 포함되어 있다면 (예, MyPrefix_MyFunc), 프로그램은 두 라이브러리를 모두 뒤져 MyPrefix.ahk라는 이름의 파일을 찾고 있다면 그것을 적재합니다. 이렇게 하면 MyPrefix.ahk에 함수 MyPrefix_MyFunc를 다음을 수있고 이름이 MyPrefix_로 시작하는 기타 함수들을 담을 수 있습니다.

[AHK_L 42+]: 지역 라이브러리가 지원됩니다. 먼저 지역 라이브러리를 검색한 다음에 사용자 라이브러리와 표준 라이브러리를 차례로 검색합니다.

MyFunc()와 같이 직접 호출 해야만 라이브러리가 자동-포함됩니다. 함수가 예를 들어 타이머나 구이 이벤트 같이, 동적 또는 간접적으로 호출될 때만, 명시적으로 라이브러리를 스크립트에 포함시켜야 합니다. 예를 들어: #Include <MyFunc>

라이브러리 파일은 일반적으로 그의 파일 이름으로 오직 하나의 함수만 담고 있지만, 사적으로 자신만 호출할 함수나 서브루틴을 담을 수도 있습니다. 그렇지만, 그런 함수는 이름이 구별되어야 합니다. 왜냐하면 그것들은 전역 이름공간 안에 여전히 존재할 것이기 때문입니다; 즉, 그것들은 스크립트 어디에서나 호출될 수 있습니다.

라이브러리 파일이 #Include를 사용하면, #Include를 위한 작업 디렉토리는 그 라이브러리 파일의 디렉토리입니다. 이를 이용하면 해당 함수와 관련 함수들이 들어 있는 더 큰 라이브러리 파일로 방향전환을 할 수 있습니다.

스크립트 컴파일러 (ahk2exe)도 라이브러리 함수를 지원합니다. 그렇지만, AutoHotkey.exe 사본이 위의 컴파일러 디렉토리에 존재해야 합니다 (보통 그럴 것입니다). AutoHotkey.exe가 없어도, 컴파일러는 여전히 작동하지만, 라이브러리 함수는 자동으로 포함되지 않습니다.

라이브러리로부터 포함된 함수들은 다른 함수와 똑같이 수행됩니다. 왜냐하면 스크립트가 실행되기 전에 미리-적재되기 때문입니다.

내장 함수

내장 함수의 매개변수 리스트 끝에 선택적인 매개변수는 완전히 생략해도 좋습니다. 예를 들어, WinExist("Untitled - Notepad")는 유효합니다. 왜냐하면 그의 다른 세 매개변수가 빈 것으로 간주되기 때문입니다.

내장 함수는 스크립트가 자신의 함수를 같은 이름으로 정의하면 오버라이드됩니다. 예를 들어, 스크립트는 자신만의 맞춤 WinExist() 함수를 가질 수 있습니다. 표준 함수 대신에 이 함수가 호출됩니다. 그렇지만, 그렇게 되면 스크립트는 원래 함수를 호출할 방법이 없어져 버립니다.

DLL 파일에 거주하는 외부 함수는 DllCall()으로 호출합니다.

자주-사용되는 함수

FileExist(FilePattern): FilePattern이 존재하지 않으면 빈 값을 (빈 문자열) 돌려줍니다 (FilePattern은 절대 경로가 지정되지 않으면 A_WorkingDir에 있다고 간주합니다). 그렇지 않으면, 부합하는 첫 파일이나 폴더의 속성 문자열을 돌려 줍니다 ("RASHNDOCT"의 하위집합). (있기 힘든 경우이지만) 파일에 아무 속성도 없으면, "X"가 반환됩니다. FilePattern는 파일이나 폴더의 정확한 이름일 수 있지만, 와일드카드(* 또는 ?)를 포함할 수도 있습니다. 빈 문자열은 "false"라고 간주되므로, 함수의 반환 값은 언제나 어림-불리언 값으로 사용할 수 있습니다. 예를 들어, 서술문 if FileExist("C:\My File.txt")는 파일이 존재하면 참이되고 그렇지 않으면 거짓이 됩니다. 비슷하게, 서술문 if InStr(FileExist("C:\My Folder"), "D")는 파일이 존재하고 그리고 디렉토이일 경우에만 참이 됩니다. 다음은 상응하는 명령어입니다: IfExist 그리고 FileGetAttrib.

GetKeyState(KeyName [, "P" or "T"]): GetKeyState 명령어와 다르게 -- 누르면 D 그리고 떼면 U를 돌려주는데 비해 -- 이 함수는 키가 눌려 있으면 참(1) 뗀 상태이면 거짓(0)을 돌려줍니다. KeyName이 유효하지 않으면, 빈 문자열이 반환됩니다. 다른 반환 값과 사용법에 관한 정보는 GetKeyState를 참조하십시오.

InStr(Haystack, Needle [, CaseSensitive = false, StartingPos = 1, Occurrence = 1]): Haystack 문자열에서 Needle이 나타난 위치를 돌려줍니다. StringGetPos와 다르게, 위치 1이 첫 번째 문자입니다; 왜냐하면 0은 "false"와 동의어이기 때문에, 직관적으로 "발견하지 못함"의 뜻이 됩니다. 매개변수 CaseSensitive를 생략하거나 거짓이면, 대소문자를 구분하지 않고 검색합니다 (대소문자의 구별은 StringCaseSense에 따릅니다); 그렇지 않으면, 대소문자가 정확하게 일치해야 합니다. StartingPos를 생략하면, 1이 기본값이 됩니다 (Haystack의 시작). 그렇지 않고, 2를 지정하면 Haystack의 두 번째 문자부터 시작하고, 3이면 세 번째 문자부터 등등 시작합니다. StartingPosHaystack의 길이를 넘어서면, 0이 반환됩니다. StartingPos가 0이거나 음수이면, 끝에서부터 해당 오프셋에서 시작하여 역방향으로 (오른쪽에서 왼쪽으로) 검색이 수행됩니다. StartingPos의 값에 관계 없이, 반환 위치는 언제나 Haystack의 첫 문자에 상대적입니다. 예를 들어, "123abc789"에서 "abc" 의 위치는 언제나 4입니다. Occurrence에 2을 지정하면 두 번째 부합한 위치를 돌려주고, 3은 세 번째 부합 등등의 위치를 돌려줍니다. 관련 항목: RegExMatch(), IfInString, 그리고 StringGetPos.

RegExMatch(Haystack, NeedleRegEx [, UnquotedOutputVar = "", StartingPos = 1]): 문자열 안에서 패턴 (정규 표현식)에 부합하는 것들을 찾습니다. 자세한 것은 RegExMatch()를 참조하십시오.

RegExReplace(Haystack, NeedleRegEx [, Replacement = "", OutputVarCount = "", Limit = -1, StartingPos = 1]): 문자열 안에서 패턴 (정규 표현식)에 부합하는 것들을 교체합니다. 자세한 것은 RegExReplace()를 참조합니다.

SubStr(String, StartingPos [, Length]) [v1.0.46+]: 부분문자열을 String으로부터 복사합니다. StartingPos에서 시작해서 오른쪽으로 진행해서 최대 Length개의 문자를 포함합니다 (Length를 생략하면, 기본 값은 "모든 문자"입니다). StartingPos에 1을 지정하면 첫 번째 문자에서, 2을 지정하면 2번째 문자부터 시작합니다. 등등. ( StartingPosString의 길이를 넘어서면, 빈 문자열이 반환됩니다). StartingPos가 1보다 작으면, 문자열 끝으로부터의 오프셋으로 간주됩니다. 예를 들어, 0은 가장 마지막 문자를 추출하고, -1이면 그 문자열의 마지막 문자로부터 1만큼 왼쪽으로 떨어져 있다고 간주됩니다. (그러나 StartingPos가 문자열의 왼쪽 끝을 넘어서 시도하면, 첫 문자부터 추출을 시작합니다). Length는 열람할 최대 문자 개수입니다 (문자열의 나머지 부분이 너무 짧으면 최대 개수보다 적게 열람됩니다). 음의 길이(Length)를 지정하면 반환된 문자열의 끝으로부터 문자를 그 개수 만큼 생략합니다 (모든 또는 너무 많은 문자를 생략하면 빈 문자열이 반환됩니다). 관련 항목: RegExMatch(), StringMid, StringLeft/Right, StringTrimLeft/Right.

StrLen(String): 문자열 String의 길이를 돌려줍니다. 자세한 것은 StrLen()을 참조합니다.

StrSplit(String [, Delimiters, OmitChars]) [v1.1.13+]: 지정된 가름자를 사용하여 문자열을 부분문자열 배열로 분할합니다. 자세한 것은 StrSplit()을 참조합니다.

WinActive([WinTitle, WinText, ExcludeTitle, ExcludeText]): 지정된 기준에 부합하는 활성 창의 Unique ID (HWND)를 돌려줍니다. 자세한 것은 WinActive()를 참조하십시오.

WinExist([WinTitle, WinText, ExcludeTitle, ExcludeText]): 첫 번째로 부합하는 창의 Unique ID (HWND)를 돌려줍니다. 자세한 것은 WinExist()를 참조하십시오.

기타 함수

Asc(String): String에서 첫 바이트 또는 UTF-16 코드 유닛의 숫치 값을 돌려줍니다. 또는 String이 비어 있으면 0을 돌려줍니다. 반환 값은 범위가 0부터 255까지입니다 (ANSI) 또는 0부터 0xFFFF까지입니다 (Unicode). 자세한 것은 Unicode vs ANSI를 참조합니다. 유니코드 보충 문자를 허용하려면, 대신에 Ord(String)를 사용하십시오.

Chr(Number): Number가 나타내는 문자 코드에 상응하는 문자를 돌려줍니다 (보통 문자 하나). 127보다 큰 문자 코드의 의미는 사용 중인 문자열 인코딩에 달려 있습니다. 문자 인코딩은 이제 사용중인 실행 파일이 Unicode 또는 ANSI인가에 따라 달라집니다. 유니코가 지원되면, Number는 0부터 0x10FFFF 사이의 유니코드 문자 코드입니다 ([v1.1.21]이전이라면 0xFFFF); 그렇지 않고 ANSI 문자 코드는 범위가 0부터 255 사이입니다. Number가 유효한 문자 코드 범위에 있지 않으면, 빈 문자열이 반환됩니다. 흔한 문자 코드로는 9 (탭), 10 (라인피드), 13 (캐리지 리턴), 32 (스페이스), 48-57 (숫자 0-9), 65-90 (대문자 A-Z), 그리고 97-122 (소문자 a-z)가 있습니다.

DllCall(): 예를 들어 표준 윈도우즈 API 함수 같이, DLL 안 함수를 호출합니다. 자세한 것은 DllCall()을 참조합니다.

FileOpen(): 객체-지향적 파일 I/O를 제공합니다. 자세한 것은 FileOpen()를 참조합니다.

Func(FunctionName) [v1.1.00+]: (예를 들어 #Include로 포함하거나 또는 라이브러리 함수를 고정 호출하여) FunctionName이 명시적으로 스크립트에 존재하지 않으면, Func()는 0을 돌려줍니다. 그렇지 않으면 그 함수를 가리키는 참조 주소를 반환합니다. 함수를 호출하거나 매개변수의 최대 최소 갯수 같은 정보를 열람하는 데 사용할 수 있습니다.

GetKeyName(Key), GetKeyVK(Key), GetKeySC(Key) [v1.1.01+]: 한 키의 스캔 코드나 가상 코드 또는 이름/텍스트를 열람합니다. Key는 "vkA2"나 "sc01D"와 같이 VK 코드나 SC 코드일 수 있습니다. 키 이름이거나 아니면 둘을 조합한 것일 수 있습니다. 예를 들어 GetKeyName("vk1B")GetKeyName("Esc") 모두 "Escape"를 돌려주는 반면에, GetKeyVK("Esc")는 27을 돌려줍니다. VK 코드와 SC 코드는 십육진수임에 유의하십시오. 십진수를 적절한 포맷으로 변환하려면, Format("vk{:x}", vk_code)이나 Format("sc{:x}", sc_code)를 사용합니다.

IsByRef(Var) [v1.1.01+]: Var가 ByRef 매개변수이고 호출자가 변수를 공급했으면 1을 돌려줍니다; 또는 Var가 다른 종류의 변수이면 0을 돌려줍니다.

IsFunc(FunctionName) [v1.0.48+]: (예를 들어 #Include로 포함하거나 또는 라이브러리 함수를 고정 호출하여) FunctionName이 스크립트에 명시적으로 존재하지 않으면, IsFunc()는 0을 돌려줍니다. 그렇지 않으면 매개변수의 최소 개수에 1을 더해 돌려줍니다 (예, 매개변수를 요구하지 않는 함수는 1, 매개변수를 1 오구하는 함수는 2, 등등). 예를 들어, if IsFunc("MyFunc")if IsFunc(VarContainingFunctionName)는 함수가 존재하면 참입니다. 그렇지 않으면 거짓입니다. v1.1.00+에서, FunctionName는 이름이 아니라 함수 참조일 수 있습니다. 다음 참조: 동적인 함수-호출, A_ThisFunc

IsLabel(LabelName): LabelName이 스크립트에 서브루틴, 핫키, 또는 핫스트링으로 존재하면 0이 아닌 값을 돌려줍니다 (LabelName 뒤에 쌍점은 포함하지 않습니다). 예를 들어, 서술문 if IsLabel(VarContainingLabelName)는 라벨이 존재하면 참입니다. 그렇지 않으면 거짓입니다. 예를 들어 Gosub, 핫키, 메뉴, 그리고 Gui와 같이 명령어에 동적 라벨을 지정할 때 실행시간 에러를 피하는 데 유용합니다. 다음도 참조하십시오: 라벨.

IsObject() [AHK_L 31+]: 값이 객체인지 결정합니다. 다음 참조: Objects.

ListView 그리고 TreeView functions: 자세한 것은 ListView 페이지와 TreeView 페이지를 참조하십시오.

NumGet(VarOrAddress [, Offset = 0][, Type = "UPtr"]): 지정된 주소+오프셋에 저장된 이진 숫자를 열람합니다. 자세한 것은 NumGet을 참조합니다.

NumPut(Number, VarOrAddress [, Offset = 0][, Type = "UPtr"]): 지정된 주소-오프셋에 이진 형식으로 숫자를 저장합니다. 자세한 것은 NumPut을 참조합니다.

OnMessage(MsgNumber [, "FunctionName"]): 메시지/이벤트를 관제합니다. 자세한 것은 OnMessage()를 참조합니다.

Ord(String) [v1.1.21+]: String에서 첫 번째 문자의 서수 값을 돌려줍니다 (숫치 문자 코드). String이 유니코드 보충 문자로 시작하면, Ord(String)은 그에 상응하는 유니코드 문자 코드를 돌려줍니다 (0x10000부터 0x10FFFF 사이의 값). 그렇지 않으면 Asc(String)과 같은 값을 돌려줍니다.

StrGet(Address [, Length] [, Encoding = None ] ) [AHK_L 46+]: 메모리 주소로부터 문자열을 복사합니다. 선택적으로 코드 페이지에 따라 변환합니다. 자세한 것은 StrGet()을 참조합니다.

StrPut(String, Address [, Length] [, Encoding = None ] ) [AHK_L 46+]: 메모리 주소에 문자열을 복사합니다. 선택적으로 코드 페이지에 따라 변환합니다. 자세한 것은 StrPut()을 참조합니다.

RegisterCallback(): 머신-코드 주소를 생성합니다. 호출될 때 이 주소를 이용하여 스크립트 안의 함수로 호출을 방향전환 합니다. 자세한 것은 RegisterCallback()을 참조합니다.

Trim() [AHK_L 31+]: 문자열의 앞/뒤에서 문자를 걷어냅니다. 자세한 것은 Trim()을 참조합니다.

VarSetCapacity(UnquotedVarName [, RequestedCapacity, FillByte]): 변수의 가용 능력을 확대하거나 그의 메모리를 해제합니다. 자세한 것은 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): Number의 상용로그를 돌려줍니다 (밑수 10). 결과는 부동 소수점 수로 포맷됩니다. Number가 음수이면, 빈 문자열이 반환됩니다.

Ln(Number): Number의 자연로그를 반환합니다 (밑수 e). 결과는 부동 소수점 수로 포맷됩니다. Number가 음수이면, 빈 문자열이 반환됩니다.

Mod(Dividend, Divisor): 나머지 연산(Modulo)입니다. 피젯수젯수로 나눈 나머지를 돌려줍니다. 결과의 부호는 언제나 첫 매개변수의 부호와 같습니다. 예를 들어, 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입니다. 두 번째 매개변수가 0이면, 함수는 빈 결과 (빈 문자열)을 돌려줍니다.

Round(Number [, N]): N을 생략하거나, 0이면, Number는 가장 가까운 정수로 반올림됩니다. N이 양수이면, NumberN 십진 자리에서 반올림됩니다. N이 음수이면, Number는 십진 소수점의 왼쪽으로 N 자리에서 반올림됩니다. 예를 들어, Round(345, -1)는 350이고 Round(345, -2)는 300 입니다. Transform Round와 다르게 , 1 보다 작거나 N을 생략하면 그 결과는 .000 꼬리가 없습니다. v1.0.44.01+에서, N의 값이 0보다 크면 SetFormat에 의존하지 않고 정확하게 N 자리의 십진수를 보여줍니다. 이를 피하려면, Round()의 반환 값에 다른 수학 연산을 수행하십시오; 예를 들어: Round(3.333, 1)+0.

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는 그의 탄젠트 값입니다).

주의: 라디안을 디그리로 변환하려면, 180/pi (대략 57.29578)를 곱합니다. 디그리를 라디안으로 변환하려면 pi/180 (대략 0.01745329252)를 곱합니다. pi의 값 (대략 3.141592653589793)은 1 아크탄젠트의 4 배입니다.

기타 함수

폴리에테네(Polyethene)의 명령어 함수: OutputVar가 있는 AutoHotkey 명령어에 호출 가능한 함수를 제공합니다. 이 라이브러리는 #Include를 통하여 스크립트에 포함할 수 있습니다.