⚠ 이 강좌는 오토핫키 v1을 다룹니다
지금 보시는 강좌는 구버전 오토핫키(v1.1)를 다루고 있습니다. 따라서 본 강좌의 내용은 현재 최신 오토핫키 버전 (v2.0)과 호환되지 않습니다. 구버전의 정보가 필요한 것이 아니라면, 가능한 한 새로운 사이트에 작성한 v2 강좌(https://ahkv2.pnal.dev)를 봐주시길 바랍니다.
[프날 오토핫키] 배열 #4: 배열과 객체
지난 강에선 단순 배열의 선언과 할당을 배웠습니다. 말이 어렵지, 일반적인 변수 사용과 거의 동일한 모습을 띠고 있었죠. 한 번 정리하고 갑시다.
[선언]
배열명 := []
[할당]
배열명[인덱스] := 할당할 값(요소)
[선언과 동시에 할당]
배열명 := [1번항목, 2번항목, ...]
크게 어렵지 않습니다. 더불어 대괄호([])도 연산자의 한 종류임을 말씀드렸죠. 따라서 지금 저기 적혀있는 배열명, 인덱스, 할당할 값(요소)은 모두 표현식으로 적혀야한다는 것까지 지난 강에서 배웠습니다.
이번에는 단순 배열에서 사용할 수 있는 몇가지 메서드를 소개해드리고자 합니다. 우리가 배열을 사용함는 이유 중 하나가 그 배열을 가공할 수 있는 여러 함수를 사용할 수 있기 때문입니다. 이번 강에서는 배열을 가공할 수 있는 그런 함수를 배워보겠습니다. 그런데 왜 함수라고 안하고 '메서드'라고 했을까요?
메서드는 뭐죠?
메서드를 이해하려면 객체가 무엇인지부터 알아야합니다. 객체는 어떤 속성이나 함수를 가지고 있는 집합입니다. 어렵게 적혀있지만 하나씩 이해해보겠습니다. 객체는 '속성'이나 '함수'를 가지고 있다고 하는데, 속성을 다른 말로 하면 객체가 가질 수 있는 성질이며, 이는 변수의 형태로 존재합니다(=속성은 객체가 가진 변수입니다.) 함수는 당연히 함수의 형태로 가지고 있겠고요. 즉, 여러 속성과 함수를 묶어놓아서 하나의 큰 덩어리로 만들어둔 개념적인 것을 '객체'라고 합니다.
우리는 이렇게 속성(변수)과 함수를 가지고 있는 '객체'라는 큰 틀을 가져와서, 그 객체 안에 있는 속성과 함수를 사용할 수 있습니다. 예를 들어서 '강아지'라는 객체의 속성은 {크기, 색상, 식성} 등이 있고, 함수는 {짖기, 먹기, 꼬리치기} 등이 있습니다. 그렇다면 우리는 '강아지'객체의 속성과 함수를 조정해준 뒤 사용해줌으로써 성질이 다른 여러 강아지들을 프로그래밍에서 이용할 수 있는 것이지요.
[Dog 객체]
속성(변수): size, color, food
함수: Bark(), Eat(), WagTail()
→ 객체는 속성과 함수가 모인 하나의 개념적인 집합입니다.
여기서 객체의 '속성(변수)'은 필드(field), '함수'는 메서드(method)라고 부릅니다. 중요하니까 다시 한 번 강조해보면, 객체의 속성을 필드, 객체의 함수는 메서드라고 부르는 것입니다. 따라서 이번에 단순 배열에서 이용할 수 있는 '메서드'를 배운다는 것은, 단순 배열은 객체이고 이 객체에서 쓸 수 있는 함수를 배우겠다는 뜻입니다.
단순 배열은 '객체'이다!
단순 배열의 메서드(함수)를 이용하면 그 배열에 여러 동작을 할 수 있다!
단순 배열을 객체... 그러니까 필드와 메서드의 집합으로 바라보세요. 이 배열이 가지고 있는 필드는 {첫번째 요소, 두번째 요소, ...} 등이 있을 것이고, 가질 수 있는 메서드는 {값 추가하기, 값 제거하기, ...} 등이 있겠네요. 즉, 우리는 배열을 조작할 수 있는 여러 함수를 배울 것입니다.
또, 필드와 메서드를 묶어서(그러니까 객체의 속성과 함수를 묶어서) '멤버'라고도 부릅니다. 즉, 멤버 변수는 '필드', 멤버 함수는 '메서드'를 이야기하는 용어인 점을 알아두어야 합니다.
필드 + 메서드 = 멤버
필드를 멤버 변수, 메서드를 멤버 함수라고도 한다!
여기까지 이해를 하시고 아래로 내려가는 것이 좋습니다. 객체(와 필드, 메서드)는 직접 부딪히기보다 머리로 이해해야하는 개념적인 것인거기에, 일단 위의 내용을 알아두셔야 앞으로 이해가 잘 될 것입니다.
객체에서 필드와 메서드를 사용하는 방법
객체가 가지고 있는 것 중 변수 형태는 '필드', 함수 형태는 '메서드'라고 부른다고 했습니다. 이들을 사용하는 방법은 간단합니다. 객체명 뒤에 '멤버 접근 연산자' 마침표(.)를 찍고, 필드를 적어주거나 메서드를 호출하면 됩니다. 예를 들어서, dog 객체의 color 필드와 Bark() 함수를 사용하고자 합니다. Bark() 함수의 매개변수는 정수(1~100)를 받는다고 가정해보자고요.
그렇다면 아래와 같이 '필드와 메서드'(=멤버)를 사용할 수 있겠네요.
dog.color ;dog객체의 색을 담고 있는 필드
dog.Bark(50) ;dog객체가 가지고 있는 '짖기' 동작을 수행할 수 있는 메서드 호출
표현식 자리에서 반환값을 볼 수 있겠습니다.
MsgBox, % dog.color
MsgBox, % dog.Bark(50)
본격적인 객체 강좌는 아니기 때문에 이론만 알아두세요. 객체지향 프로그래밍과 관련된 여러 개념들은 나중에 기회가 있다면 따로 강좌하겠습니다. 아무튼 오토핫키 기준으로 배열도 객체의 한 종류이기 때문에, 이와 같이 배열의 필드와 메서드에 접근할 수 있습니다.
단순 배열에서 쓸 수 있는 메서드
단순 배열에서 쓸 수 있는 메서드는 많습니다. 자세한 것은 래퍼런스의 Object 문서를 참고하세요. 프날에선 자주 쓰이는 몇 가지 메서드만 적도록 하겠습니다.
메서드 | 매개변수 | 반환값 | 역할 |
Push() | 넣을 값 | 넣은 값이 가지는 인덱스 | 마지막에 값 넣기 |
Pop() | - | 추출한 값 | 마지막 값 추출하기 |
InsertAt() | 삽입할 위치, 삽입할 값 | - | 특정 인덱스에 값 넣기 |
RemoveAt() | 지울 위치, 지울 길이 | 지워진 값의 개수(1개일 경우, 지워진 값의 인덱스) | 특정 인덱스의 값 제거하기 |
Length() | - | 배열의 길이 | 배열의 길이 반환 |
하나씩 알아보도록 합시다.
1. Push() / Pop()
Push() 메서드는 배열의 끝에 값을 추가하는 역할입니다. 즉, 아래와 같은 단순 배열이 있다면
arr := [2, 4, 6]
여기에 Push() 함수를 이용해서 마지막에 값을 넣을 수 있습니다.
arr.Push(8)
→ arr[4]는 8의 값을 가질 것입니다. (실행 후 arr의 모습: [2, 4, 6, 8])
단순 배열은 '객체'에 속하기 때문에, 이와 같이 멤버 접근 연산자(.) 뒤에 함수를 적어주어 메서드 호출이 가능합니다. (바로 앞 소제목에서 설명드린 내용입니다.) 우리가 객체의 메서드를 호출한 것입니다!
Pop() 메서드는 배열의 마지막 값을 추출해오는 역할을 합니다. 추출된 값은 사라지고요. 위쪽의 arr 배열에 적용시켜보면 (지금 2, 4, 6, 8의 값을 가지고 있습니다.)
MsgBox, % arr.Pop()
→ arr의 마지막 값인 8을 반환하고, 그 값을 지웁니다. (실행 후 arr의 모습: [2, 4, 6])
이렇게 마지막 값을 추출할 수 있습니다.
2. InsertAt() / RemoveAt()
InsertAt() 메서드는 특정 인덱스에 값을 추가하는 역할을 합니다. 위의 arr배열을 그대로 이용해보면 (현재: [2, 4, 6])
arr.InsertAt(3, "테스트")
arr.InsertAt(3, 5)
두 줄을 넣었을 때의 arr배열은 [2, 4, 5, "테스트", 6]의 형태를 띠게 됩니다. 이해가 잘 안되면 그림으로 보는게 편합니다.
원래 배열이 위 그림처럼 [2, 4, 6]의 형태로 구성되어 있었는데, 첫 줄의 arr.InsertAt(3, "테스트")를 만나면 아래와 같이 변합니다.
테스트라는 문자열이 세 번째 위치에 삽입된 것을 볼 수 있습니다. 여기서 두 번째 줄인 InsertAt(3, 5)를 만나면
이렇게 숫자 5가 세 번째 인덱스로 삽입되는 것을 볼 수 있습니다. 이렇듯 InsertAt()은 지정된 인덱스에 배열값을 삽입하는 동작을 한다는 것을 알아두세요. 물론, 여러 값을 한 번에 추가할 수 있습니다. InsertAt(인덱스, 값1, 값2, 값3...)처럼 이어서 값을 써주면, 각 인덱스에 알맞게 잘 삽입됩니다. 3번 인덱스로 지정해주고 3개의 값을 넣어주면, 3,4,5번 인덱스에 값이 채워지겠지요.
RemoveAt()도 마찬가지입니다. 지정된 인덱스의 값을 제거하는 함수입니다. 인덱스만 지정해주면 잘 제거해줍니다. 지울 항목 개수를 적어주면 그만큼의 항목을 제거합니다. RemoveAt(4, 2)는 네번째 인덱스에서 두 항목을 지우겠죠. (길이를 생략하면 그 인덱스의 항목만 지웁니다.)
3. Length()
배열의 길이를 반환합니다. 10개의 항목이 있다면 10, 20개의 항목이 있다면 20을 반환합니다.
중간에 공백값(빈 값)이 있어도 포함하여 가져옵니다. 따라서, arr[1]과 arr[20]에 값이 있고 만약 arr[2]~arr[19]이 비어있다고 해도, 20을 반환합니다.
Loop의 Count 매개변수는 전통식 자리입니다. 메서드 호출할때 표현식 자리로 고쳐서 호출해주면 되겠죠? 아래와 같은 테크닉을 통해 배열의 길이를 몰라도 배열 전체를 탐색할 수 있습니다.
Loop, % arr.Length()
{
MsgBox, % arr[A_index]
}
단순 배열에서 사용할 수 있는 5개의 메서드를 말씀드렸습니다. 이 5개는 자주 쓰게되므로 꼭 알아두세요. 이 메서드를 사용한 예제도 준비하였습니다. 소스코드를 다운 받아서 실행시켜보세요. 각 메서드를 지난 후 배열의 값이 어떻게 변화하는지를 중점으로 살펴보시면 좋습니다.
Q. 배열이 객체라고 한 것은 이해했고, 배열의 속성(필드)은 {첫번째 요소, 두번째 요소, ...}등이 있다고 언급된 것도 이해했습니다. 그런데 강좌에서 멤버 접근 연산자로 배열의 '메서드'(Push(), Pop() 등)에만 접근했지, 배열의 멤버 변수인 '필드'에는 접근을 하지 않은 것 같습니다. 그렇다면 멤버 접근 연산자(.)를 이용해서 배열의 필드(각 요소)에 접근할 수도 있나요?
A. 네. 그동안 배열의 첫번째 값, 두번째 값과 같은 인덱스 접근을 대괄호[]로 해왔죠. 대괄호(첨자 연산자)는 배열에서만 사용할 수 있습니다. 그러나 배열은 객체이기에 멤버 접근 연산자(.)로도 각 항목에 접근할 수 있겠지요.
따라서 arr[1]은 결국 arr.1로도 접근할 수 있습니다. 다만 타언어의 경우 안되는 경우가 많으니 오토핫키 배열의 특성이라고 생각하셔도 좋습니다. 애초에 다른 프로그래밍 언어에서는 필드명이 숫자로 시작하는 것을 허용하지 않는 경우가 많거든요. 그래서 오토핫키에선 멤버 접근 연산자로 배열의 필드에 접근할 수 있지만, 가독성과 타 언어와의 통일성을 위해서 첨자 연산자(대괄호)를 사용해주세요.
Q. 타언어 하다왔는데요, 배열이 객체라고요? 왜죠? 그러면 객체는 배열인가요?
A. 오토핫키에서 배열이 객체의 형태로 구현된 이유는 그냥 만든 사람이 그렇게 만들었기 때문입니다(Object-based Arrays라고 합니다.) 자바스크립트와 거의 동일한 구현이죠. 배열이 객체라고 해서, 객체가 배열인 것은 아닙니다. 객체가 더 큰 개념이고, 마치 '고양이'는 '동물'에 속하지만 '동물'은 '고양이'에 속하지 않는 것처럼 포함관계가 명확합니다. 따라서 오토핫키에선 배열은 객체로 만들어져있지만, 객체는 배열이 아닐수도 있습니다. 혹시 타언어에서 Dictionary(딕셔너리)나 List(리스트) 라는 개념을 보셨다면, 이건 오토핫키처럼 객체일 가능성이 높습니다. 오토핫키의 배열은 타언어의 딕셔너리(혹은 리스트)와 유사합니다.