함수 선언

함수 선언

함수 선언은 우리 코드에 "이 이름으로 부를 수 있는 동작"을 하나 정의해 주는 문법이에요. 이름을 붙여 두면 나중에 그 이름만으로 원하는 동작을 실행할 수 있죠. 그런데 함수 하나를 쓸 때도 문법이 제법 정해져 있어요. 이 섹션에서는 함수를 선언하는 방식과 지켜야 할 규칙 몇 가지를 함께 볼게요.

출처: Go Specification

본문

함수 선언(Function declaration)은 **함수 이름(function name)**이라는 식별자를 하나의 함수에 묶어 줘요. 즉 이름과 동작을 연결하는 선언이라는 뜻이에요. 형식은 EBNF로 이렇게 정의돼요.

FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] .
FunctionName = identifier .
FunctionBody = Block .

우리가 평소에 쓰는 func add(a, b int) int { ... } 같은 문장이 곧 이 FunctionDecl 규칙을 따르는 거예요. func 키워드로 시작해서 이름, 시그니처, 그리고 선택적으로 본문이 붙죠.

여기서 주의할 규칙이 하나 있어요. 함수의 **시그니처가 결과 매개변수(result parameters)**를 선언한다면, 함수 본문의 문장 목록은 반드시 종결 문장(terminating statement)으로 끝나야 해요. 예를 들어 반환값이 있는 함수인데 끝까지 도달해 버리면 컴파일러가 잡아 줘요.

func IndexRune(s string, r rune) int {
	for i, c := range s {
		if c == r {
			return i
		}
	}
	// invalid: missing return statement
}

위 코드에서 r을 못 찾고 루프를 다 돌고 나면 함수 끝에 도달하게 되는데, 이 경우 반환값을 돌려주지 못하니까 missing return statement 오류가 나요.

또 함수 선언이 타입 매개변수(type parameters)를 지정하면, 그 함수 이름은 **제네릭 함수(generic function)**를 가리키게 돼요 [Go 1.18]. 제네릭 함수는 호출하거나 값으로 사용하기 전에 반드시 인스턴스화(instantiated)해야 해요.

func min[T ~int|~float64](x, y T) T {
	if x < y {
		return x
	}
	return y
}

이런 min 함수는 int도, float64도 받을 수 있는 제네릭 함수예요. 실제로 값을 넣어 호출할 때 타입이 정해지면서 인스턴스화가 일어나요.

한 가지 더, 타입 매개변수가 없는 함수 선언은 본문을 생략할 수 있어요. 이런 선언은 Go 바깥에서 구현된 함수, 예를 들어 어셈블리 루틴의 시그니처만을 제공해 줘요.

func flushICache(begin, end uintptr)  // implemented externally

flushICache는 본문이 없지만 시그니처는 있어서, Go 바깥(주로 어셈블리)에서 실제 구현을 채워 넣는 식으로 쓰여요.

더 알아보기