1 함수 기본 사항

프로그래밍에서 함수는 특정 작업을 수행하는 코드 조각이며 입력 매개변수와 반환 값을 가질 수 있습니다. Go 언어에서 함수는 코드를 구성하고 재사용하는 데 널리 사용됩니다. 함수를 효과적으로 사용하면 코드를 더 간결하고 가독성 있게 만들 수 있으며 유지보수도 쉬워집니다.

함수는 Go 언어의 핵심 구성 요소이며 함수를 선언하고 정의하는 방법을 이해하는 것은 효율적이고 가독성 있는 코드를 작성하는 데 중요합니다.

2 함수 정의

2.1 함수 선언

Go 언어에서 함수 선언의 일반적인 형식은 다음과 같습니다:

func 함수이름(매개변수) 반환타입 {
    // 함수 본문
}

이러한 구성 요소를 살펴보겠습니다:

  1. func 키워드는 함수를 선언하는 데 사용됩니다.
  2. 함수이름은 함수의 이름으로, Go 언어의 네이밍 규칙을 따릅니다. 첫 글자가 대문자인 함수는 외부 패키지에서도 볼 수 있는 내보낼 수 있는 함수이며, 소문자로 시작하는 함수는 내보내지지 않으며 동일한 패키지 내에서만 사용할 수 있습니다.
  3. 매개변수는 함수가 받는 매개변수의 목록으로 쉼표로 구분됩니다. 각 매개변수의 유형을 지정해야 하며, 여러 매개변수가 동일한 유형인 경우 유형을 한 번만 지정할 수 있습니다.
  4. 반환타입은 함수의 반환 값의 유형입니다. 함수가 값을 반환하지 않는 경우 이 부분은 생략할 수 있습니다. 함수가 여러 값을 반환하는 경우 이 값을 괄호로 묶어야 합니다.

예를 들어, 두 정수의 합을 계산하는 간단한 함수를 선언할 수 있습니다:

func Add(a int, b int) int {
    return a + b
}

이 예에서 함수 이름은 Add이며, int 유형의 두 매개변수(a와 b)를 가지며 반환 유형은 int입니다.

2.2 매개변수 목록

매개변수 목록은 함수가 받는 매개변수와 각 매개변수의 유형을 정의합니다. 매개변수는 함수에 데이터를 전달하는 데 사용되는 특수한 종류의 변수입니다.

func Greet(name string, age int) {
    fmt.Printf("안녕, %s! 너는 %d살이야.\n", name, age)
}

Greet 함수에서 nameage는 매개변수입니다. name의 유형은 string이고, age의 유형은 int입니다. 이 함수를 호출할 때는 이러한 매개변수에 대한 실제 값이 제공되어야 합니다.

2.3 반환 유형

함수는 계산된 결과를 반환할 수 있으며 반환 유형은 함수의 반환 값의 데이터 유형을 정의합니다. 함수는 반환 값이 없을 수도 있고 하나 이상의 반환 값을 가질 수도 있습니다.

함수가 여러 값을 반환하는 경우 선언 시 이들의 유형을 괄호로 묶어야 합니다:

func Divide(dividend, divisor float64) (float64, error) {
    if divisor == 0 {
        return 0, errors.New("0으로 나눌 수 없음")
    }
    return dividend / divisor, nil
}

여기서 Divide 함수는 두 가지 값을 반환합니다: 나눗셈 결과와 오류 메시지입니다. 만약 나누는 수가 0이라면 오류가 반환됩니다.

2.4 가변 매개변수

Golang에서 함수를 정의할 때 호출자가 전달할 매개변수의 수를 정확히 모를 때 가변 매개변수를 사용할 수 있습니다. 가변 매개변수는 ...으로 표시되며, 함수가 임의의 수의 매개변수를 받을 수 있음을 의미합니다. 이것은 데이터의 불확실한 양을 다룰 때, 형식 지정, 요약 또는 순환 기능과 같은 일부 함수를 구현할 때 매우 유용합니다.

적용 시나리오

가변 매개변수는 다음과 같은 시나리오에서 일반적으로 사용됩니다:

  1. 문자열 연결: fmt.Sprintfstrings.Join과 같은 함수에서 사용됩니다.
  2. 배열/슬라이스 처리: 가변 길이의 배열 또는 슬라이스를 처리할 때 사용됩니다. 예를 들어 합계 계산이나 여러 슬라이스 연결 작업 등에 사용됩니다.
  3. 로그 및 오류 처리: 여러 오류를 처리하거나 여러 로그 정보를 기록할 때 사용됩니다. log.Printf나 사용자 지정 오류 요약 함수 등에 사용됩니다.
  4. 헬퍼 함수: API 또는 라이브러리에서 사용자에게 더 유연한 방식으로 함수를 호출할 수 있는 기능을 제공하는 데 사용됩니다.

가변 매개변수 사용

가변 매개변수를 사용하는 간단한 예제입니다:

// 정수 매개변수의 가변 수를 가져와서 그 합을 반환하는 함수 정의
func Sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

func main() {
    // 원하는 수의 매개변수를 전달할 수 있습니다
    fmt.Println(Sum(1, 2))          // 출력: 3
    fmt.Println(Sum(1, 2, 3, 4))    // 출력: 10
    
    // 슬라이스를 전달하고 슬라이스 뒤에 ellipsis(...)를 사용할 수도 있습니다
    numbers := []int{1, 2, 3, 4, 5}
    fmt.Println(Sum(numbers...))    // 출력: 15
}

Sum 함수에서 numsSum 함수에 전달된 모든 매개변수를 포함하는 정수의 슬라이스입니다. 이 슬라이스를 반복문으로 순회하고 합계를 계산할 수 있습니다.

함수 내부의 가변 매개변수는 사실상 슬라이스이므로 슬라이스 관련 작업을 모두 사용할 수 있다는 점을 주목해야 합니다. 함수에 슬라이스를 가변 매개변수로 전달해야 하는 경우 슬라이스 뒤에 ellipsis ...를 추가하면 됩니다.

가변 매개변수를 사용하면 함수 호출이 더 유연하고 간결해질 수 있지만, 가변 매개변수를 사용하는 경우 슬라이스 생성과 메모리 할당이 필요하기 때문에 약간의 성능 저하가 발생할 수 있습니다. 따라서 엄격한 성능 요구 사항이 있는 경우에는 주의가 필요합니다.

팁: 슬라이스에 대한 자세한 설명은 후속 장에서 제공됩니다. 다른 프로그래밍 언어를 경험한 적이 있는 경우 일시적으로 배열로 생각해도 됩니다.

3 함수 호출

3.1 기본 함수 호출

함수 호출은 함수의 코드를 실행하는 것을 의미합니다. Go에서 정의된 함수를 호출하는 것은 매우 간단합니다. 함수 이름을 사용하고 적절한 매개변수를 전달하면 됩니다. 예를 들어:

result := add(3, 4)
fmt.Println(result)  // 출력: 7

이 예제에서는 add 함수가 호출되고 두 정수가 매개변수로 전달되며, 그 후 반환된 결과가 result 변수에 할당됩니다.

3.2 매개변수 전달

함수에 매개변수를 전달할 때, Go는 기본적으로 값을 복사하여 전달하는 pass-by-value를 사용합니다. 즉, 매개변수 값의 사본이 전달되고 원래 데이터는 변경되지 않습니다. 그러나 함수가 외부 변수를 수정하거나 성능상의 이유로 pass-by-reference를 사용하려면 포인터를 사용하거나 큰 구조체를 전달하는 등의 방법을 사용할 수 있습니다.

값으로 전달하는 예와 참조로 전달하는 예는 다음과 같습니다:

// 값으로 전달하는 예
func double(val int) {
    val *= 2
}

// 참조로 전달하는 예
func doublePtr(val *int) {
    *val *= 2
}

func main() {
    value := 3
    double(value)
    fmt.Println(value)  // 출력: 3, 값은 변경되지 않음

    doublePtr(&value)
    fmt.Println(value)  // 출력: 6, 값이 두 배로 변경됨
}

위 예제에서 double 함수는 전달된 val을 두 배로 하려고 시도하지만, 그것은 복사본만 두 배로 하고 원래의 value 변수는 변경되지 않습니다. 그러나 doublePtr 함수는 정수 변수의 포인터를 매개변수로 받아 원본 변수의 값을 변경합니다.