함수·메서드 호출
함수·메서드 호출 (Calls)
함수를 호출하는 건 Go에서 가장 자주 하는 일일 텐데요, 그 호출이 정확히 어떤 동작으로 이어지는지 짚어볼게요. 함수형 타입의 값 뒤에 인자 목록을 붙이면 그 함수가 호출되고, 메서드 호출은 리시버 타입 위의 셀렉터로 메서드를 지정한다는 점만 다릅니다. 지금부터 그 규칙을 하나씩 살펴봐요.
출처: Go Specification
본문
함수형 function type을 갖는 표현식 f가 있을 때,
f(a1, a2, … an)
는 f를 인자 a1, a2, … an으로 호출합니다. 딱 하나의 특수한 경우를 빼면, 인자는 반드시 단일 값 표현식이어야 하고, F의 파라미터 타입에 assignable해야 하며, 함수가 호출되기 전에 평가됩니다. 이 호출 표현식의 타입은 F의 결과 타입입니다. 메서드 호출도 비슷하지만, 메서드 자체가 메서드의 리시버 타입을 가진 값 위의 셀렉터로 지정된다는 점이 다릅니다.
math.Atan2(x, y) // function call
var pt *Point
pt.Scale(3.5) // method call with receiver pt
f가 제네릭 함수를 나타내면, 호출하거나 함수 값으로 쓰기 전에 반드시 instantiated되어 있어야 합니다.
f의 타입이 type parameter인 경우, 그 타입 집합에 속한 모든 타입은 동일한 기본 타입을 가져야 하고, 그 기본 타입은 함수 타입이어야 하며, 함수 호출이 그 타입에 대해 유효해야 합니다.
함수 호출에서 함수 값과 인자는 the usual order대로 평가됩니다. 평가가 끝나면 함수의 variables—파라미터와 결과를 포함해서—를 위한 새 저장 공간이 할당됩니다. 그런 다음 호출의 인자가 함수로 *전달(passed)*되는데, 이는 인자가 해당하는 함수 파라미터에 assigned되고, 호출된 함수가 실행을 시작한다는 뜻입니다. 함수가 반환될 때 함수의 반환 파라미터는 호출한 쪽으로 다시 전달됩니다.
nil 함수 값을 호출하면 run-time panic이 발생합니다.
특수한 경우로, 함수 또는 메서드 g의 반환 값이 다른 함수 또는 메서드 f의 파라미터와 개수가 같고 하나하나 assignable하다면, 호출 f(g(<i>parameters_of_g</i>))은 g의 반환 값을 순서대로 f의 파라미터에 전달한 뒤 f를 호출합니다. f의 호출에는 g의 호출 말고 다른 파라미터가 있어서는 안 되고, g는 반환 값을 적어도 하나 가져야 합니다. f에 마지막 ... 파라미터가 있다면, 보통 파라미터에 할당하고 남은 g의 반환 값들이 그 파라미터에 할당됩니다.
func Split(s string, pos int) (string, string) {
return s[0:pos], s[pos:]
}
func Join(s, t string) string {
return s + t
}
if Join(Split(value, len(value)/2)) != value {
log.Panic("test fails")
}
메서드 호출 x.m()은 x의 (타입의) method set이 m을 포함하고, 인자 목록을 m의 파라미터 목록에 할당할 수 있을 때 유효합니다. x가 addressable하고 &x의 메서드 집합이 m을 포함한다면, x.m()은 (&x).m()의 줄임말입니다:
var p Point
p.Scale(3.5)
별도의 메서드 타입은 없고, 메서드 리터럴도 없습니다.
더 알아보기
- 인자를 가변 개수
...파라미터로 넘기는 규칙은 Passing arguments to...parameters에서 다뤄요. - 제네릭 함수 호출 전에 필요한 구체 타입 확정은 Instantiations를 참고해요.
- 인자가 함수에 전달되기 전에 어떤 순서로 평가되는지는 Order of evaluation에서 확인할 수 있어요.