⚠ 이 강좌는 오토핫키 v2를 다룹니다
지금 보시는 강좌는 과거 오랜 시간동안 알려진 오토핫키(v1.1)의 차세대 버전인 오토핫키 v2를 다루고 있습니다.
만약 구버전인 '오토핫키 v1.1'의 강좌를 찾으신다면 프날 오토핫키 강좌(https://pnal.kr)를 봐주시면 되지만,
새로 오토핫키를 배우신다면 v2 버전을 배우시는 것을 강력히 추천드립니다.
55. 참조에 의한 호출
마지막 수정일: 2023-12-17
함수를 사용할 때 알면 좋은 '값에 의한 호출'과 '참조에 의한 호출'에 대해서 배워봅시다. 지난 강에서 배운 '참조'를 반드시 알아야 이해하기 쉽습니다.
값에 의한 호출
일반적인 경우에, 변수는 그 자체가 아닌 값을 이용합니다. 아래와 같은 스크립트를 보겠습니다.
1 a := 1
2 Foo(a)
3 MsgBox(a)
4
5 Foo(param)
6 {
7 param := 2
8 }
함수를 호출할 땐 변수 자체가 아니라 변수의 값이 매개변수에 복사됩니다. 그래서 함수 내부에서 매개변수의 값을 바꿔도, 인수로 전달된 변수는 아무런 변화가 없습니다. 위의 예시는 그래서 1이 출력됩니다.
이렇게 변수를 사용하면 일반적으로 그 값을 사용합니다. 이것은 우리가 지금까지 써왔던 변수의 당연한 성질입니다. 이렇게 일반적으로 값이 복사되어 매개변수로 전달되는 방식을 값에 의한 호출라고 합니다.
참조에 의한 호출
매개변수에 참조를 전달할 수 있습니다. 즉, 아래와 같은 경우가 있습니다.
1 a := 1
2 Foo(&a)
3 MsgBox(a)
4
5 Foo(param)
6 {
7 %param% := 2
8 }
이 경우엔 아까와 다르게 2가 출력됩니다. 함수 내부에서 값을 바꿨음에도 불구하고, 인수로 전달해준 변수의 값이 변경된 것이죠. 왜 그럴까요? 지난 강에서 배운 참조와 역참조를 떠올려봅시다.
함수의 인수로 &a
를 전달했습니다. 한마디로 param
은 a
를 참조하고 있다는 것이지요.
참조인 param
을 다시 역참조하면 a
를 이용할 수 있습니다.
결국 함수 내부에서도 함수 바깥에 있는 a
의 값을 변경할 수 있게 되었습니다.
지난 강에서 배웠듯이, a
의 참조를 param
으로 복사하여 다시 역참조하면 결국 a
와 같습니다.
이렇게 인수로 '참조'를 전달해주는 함수 호출 방식을 참조에 의한 호출이라고 합니다.
참조에 의한 호출의 장점
보시다싶이 참조를 인수로 넘겨준다면, 인수로 넘겨준 변수의 값을 함수 내부에서 수정할 수 있습니다. 만약 이것이 불가능했다면 수정한 값을 다시 반환하여 함수 바깥에서 대입해주어야 했을 것입니다. 이런 참조에 의한 호출을 사용하여 얻는 이점이 몇가지 있습니다.
- 참조에 의한 호출을 이용하면 반환값을 사용하지 않아도 여러 값을 변경할 수 있습니다.
- 크기가 큰 값을 매개변수로 복사할 필요가 없기 때문에 성능상 이득이 됩니다.
참조에 의한 호출을 사용했던 대표적인 경우가 37강에서 배운 MouseGetPos
입니다.
MouseGetPos
는 현재 마우스 커서의 좌표를 가져와주는 함수로, 아래와 같이 사용했었습니다.
1 MouseGetPos(&vx, &vy)
인수에 쓰인 참조 연산자(&
)가 보이시나요?
왜 우리는 이 함수에게 참조를 넘겨주었을까요?
바로 "매개변수로 전달된 변수의 값을 함수 내부에서 바꿔주기 위해" 입니다.
위와 같이MouseGetPos
를 호출하면, 변수 vx
와 vy
에 현재 마우스의 x, y 좌표가 담겼습니다.
즉, (어딘가에 있는) MouseGetPos
함수의 정의에서 인수로 전달된 &vx
, &vy
를 역참조하여 그 값을 수정해줄 것입니다.
그러면 vx
, vy
의 값이 수정된 셈이죠.
이해가 되시나요?
함수는 원칙적으로 한 가지 값만 반환할 수 있습니다.
return vx, vy
같이 사용할 순 없습니다.
그렇기에, 두 가지 이상의 값을 호출부에게 알려주어야 하는 MouseGetPos
같은 함수는 '참조에 의한 호출'을 이용했습니다.
성공적으로 마우스 커서의 x좌표와 y좌표를 변수에 담아줄 수 있었죠.
또, 참조에 의한 호출을 사용하면 인수로 큰 값을 전달했을 때 그 값을 직접 매개변수로 복사할 필요가 없으므로 성능상 이점을 얻을 수 있습니다. 매개변수로 복사되는 것은 '참조'이지, '값' 자체가 아니기 때문입니다. 어마어마하게 큰 문자열 같은 경우엔 아래와 같이 참조로 전달하는 편이 성능상 좋습니다. 그렇지 않으면 함수를 호출할 때마다 큰 문자열이 매번 함수의 매개변수로 복사될 것입니다.
1 hugeString := "문자열 400만자"
2 Foo(&hugeString)
3
4 Foo(haystack)
5 {
6 함수의 본문
7 }
⚠ 참조에 의한 호출의 남용
전역 변수를 남용하면 안되는 이유와 마찬가지로, 참조에 의한 호출을 사용하면 코드의 강건성이 떨어지기 때문에 이를 남용하면 안됩니다. 함수 내부에서 바깥의 값을 자유롭게 수정할 수 있기 때문에, 의도치 않게 값을 변경하는 실수를 저지르기도 하기 때문입니다.
따라서 꼭 필요한 경우(두 개 이상의 값을 수정해야 하는 경우 등)에만 참조에 의한 호출을 사용하세요.
참조 매개변수
지금까지 배운 바로는, 참조를 함수에 넘겨주면 매번 그것을 역참조하여 사용해주어야 했습니다.
1 Foo(&bar, &baz)
2
3 Foo(param1, param2)
4 {
5 %param1% := 2
6 MsgBox(%param2%)
7 }
그렇지만 만약 함수를 정의할 때 참조만 전달받을 수 있도록 '참조 매개변수'를 지정해준다면, 역참조하지 않아도 참조하는 변수를 바로 이용할 수 있습니다. 매개변수를 받자 마자 자동으로 역참조되는 셈이죠.
함수의 정의에서 매개변수의 앞에 참조 연산자(&
)를 붙여주기만 하면 참조 매개변수를 지정할 수 있습니다.
1 Foo(&bar, &baz)
2
3 Foo(¶m1, ¶m2) ;참조 매개변수로 지정
4 {
5 param1 := 2
6 MsgBox(param2)
7 }
위의 예시에선 param1
과 param2
모두 매개변수 앞에 &
연산자를 써서 참조 매개변수를 지정해주었습니다.
따라서 역참조해주지 않고 매개변수를 이용하는 모습을 볼 수 있습니다.
참조 매개변수는 받는 순간 역참조 된 셈으로, 일일이 역참조 해줄 필요가 없습니다.
즉, 여러분은 역참조 연산자를 쓸 일이 거의 없습니다. 참조를 사용하는 가장 큰 이유는 '참조에 의한 호출'을 하기 위함인데, 참조에 의한 호출에선 매개변수를 참조 매개변수로 지정해줄 수 있으니까요. 결국 위의 예제처럼 간단하게 사용하시면 됩니다. 일일이 역참조 하며 쓰지 마세요!