Go 언어 스터디 - (4) 함수

이전 글에서 변수 선언를 선언할때 var [변수명] [타입]과 같은 형태로 선언 한다는 것이 가장 기본적인 형태라고 설명했는데 함수도 이와 크게 다르지 않다. 아래는 두 정수 x, y를 입력받아 합을 반환하는 간단한 함수다.

func add(x int, y int) int {
    return x + y
}
func add(x int, y int) int {
    return x + y
}

위 구조를 보면 알겠지만 func [함수명(함수 인자)] [반환 데이터 타입] 형태로 함수를 선언한다.

이 함수를 조금 수정해서 아래와 같이 반환할 데이터 타입을 생략해도 될까?

func add(x int, y int) {
    return x + y
}
func add(x int, y int) {
    return x + y
}

답은 "안된다". 함수는 변수와 다르게 반환할 타입까지는 추론해주지 않으므로 반환할 데이터 타입이 명시되어 있지 않다면 void, 즉 아무것도 반환하지 않는 함수로 선언된다.

함수 인자의 데이터 타입 생략

만약 함수 인자들이 2개 이상일 때, 연속적으로 나열된 인자들이 같은ㅍ 타입이라면 마지막 인자에만 타입을 명시해주면 된다. 나는 설명을 잘 못하는 편이니 이 문장이 이해가 안 된다면 매우 정상이니 그냥 아래 코드를 보자.

func someFunc(a, b, c int, s, z string) int {
    // ...
}
func someFunc(a, b, c int, s, z string) int {
    // ...
}

위의 함수 선언을 보면 함수 인자 a, b와 s는 타입이 명시되어 있지 않다. 하지만 이 코드는 정상이다. 이렇게 함수 인자가 명시되어 있지 않을 때는 그 뒤로 가장 처음 만나는 타입이 그 인자의 타입이 된다. 다시 말해 a, b, c는 int이며, s와 z는 string이다.

그래서 위 함수를 길게 늘여 쓰면 아래와 같다. 이 두 함수 선언은 정확히 같다.

func someFunc(a int, b int, c int, s string, z string) int {
    // ...
}
func someFunc(a int, b int, c int, s string, z string) int {
    // ...
}

하지만 이런 경우에는 함수 인자의 타입을 알아낼 수 없어 오류가 발생하니 유의하자.

// 오류: s와 z의 데이터 타입이 명시되어 있지 않음!
func someFunc(a, b, c int, s, z) int {
    // ...
}
// 오류: s와 z의 데이터 타입이 명시되어 있지 않음!
func someFunc(a, b, c int, s, z) int {
    // ...
}

익명 함수

익명 함수 혹은 함수 표현식이라 불리는 것도 지원한다.

아래는 간단한 익명 함수이다. Go에서 함수들은 일급 함수로 취급되어 변수에 함수를 담을 수 있는데, 이 부분은 아래에서 설명할 예정이니 지금은 코드만 보자.

sayHi := func() {
    fmt.Println("안녕!")
}

sayHi()
// 출력: 안녕!
sayHi := func() {
    fmt.Println("안녕!")
}

sayHi()
// 출력: 안녕!

위에서 선언한 함수는 이름이 없지만 sayHi 변수에 함수를 담고 sayHi를 함수 호출하듯이 코드를 작성했더니 정상적으로 함수가 실행되었다. 이는 변수에 함수가 담기면서 변수 타입도 함수가 되어 가능한 것이다.

물론 즉시 실행되는 함수 표현식(IIFE: Immediately Invoked Function Expression) 역시 사용 가능하다. 아래와 같이 익명 함수를 선언하고 함수 선언 종료 뒤에 ()를 붙여 바로 호출해주면 된다.

func main() {
    func() {
        fmt.Println("안녕!")
    }()
}
func main() {
    func() {
        fmt.Println("안녕!")
    }()
}

익명 함수에 인자를 넘기는 경우에는 아래와 같이 하면 된다. :)

func main() {
    func(text string) {
        fmt.Println(text)
    }("잘가!")
}
func main() {
    func(text string) {
        fmt.Println(text)
    }("잘가!")
}

일급 함수

Go에서 함수는 일급 함수로 취급된다. 즉, 아래와 같은 조건들을 만족한다.

  • 함수를 변수에 담을 수 있다.
  • 함수를 다른 함수의 인자로 전달할 수 있다.
  • 함수의 반환값으로 함수를 반환할 수 있다.

그 외의 조건이 몇 개 더 있지만, 그 조건들은 사람들마다 의견이 분분하므로 제외한다.

아무튼 함수들이 일급 함수로 취급되므로 아래와 같이 커링도 적용할 수 있다.

func add(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
}

add(11)(22)
// 결과: 33

fivePlus := add(5)
fivePlus(9)
// 결과: 14
func add(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
}

add(11)(22)
// 결과: 33

fivePlus := add(5)
fivePlus(9)
// 결과: 14