함수 만들기

완료됨

Go에서 함수를 사용하면 애플리케이션의 다른 부분에서 호출할 수 있는 일련의 문을 그룹화할 수 있습니다. 여러 문을 포함하는 프로그램을 만드는 대신 함수를 사용하여 코드를 구성하고 더 읽기 쉽게 만들 수 있습니다. 더 읽기 쉬운 코드는 유지 관리도 더 쉽습니다.

지금까지 fmt.Println() 함수를 호출했으며 main() 함수에서 코드를 작성했습니다. 이 섹션에서는 사용자 지정 함수를 만드는 방법을 살펴봅니다. 또한 Go에서 함수와 함께 사용할 수 있는 몇 가지 다른 기법도 살펴보겠습니다.

main 함수

지금까지 상호 작용한 함수는 main() 함수입니다. Go의 모든 실행 프로그램에는 이 함수가 있는데, 이것이 프로그램의 시작점이기 때문입니다. main() 함수는 프로그램에서 하나만 사용할 수 있습니다. Go 패키지를 만드는 경우에는 main() 함수를 작성할 필요가 없습니다. 이후 모듈에서 패키지를 만드는 방법에 대해 살펴보겠습니다.

Go에서 사용자 지정 함수를 만드는 기본 사항으로 이동하기 전에 main() 함수의 중요한 측면을 살펴보겠습니다. 이미 파악했을 수 있겠지만, main() 함수는 매개 변수를 가지고 있지 않으며 아무것도 반환하지 않습니다. 그러나 명령줄 인수와 같은 사용자의 값을 읽을 수 없다는 의미는 아닙니다. Go에서 명령줄 인수에 액세스해야 하는 경우 os 패키지os.Args 변수(프로그램에 전달되는 모든 인수 포함)를 사용하여 그렇게 할 수 있습니다.

다음 코드는 명령줄에서 두 개의 숫자를 읽고 합산합니다.

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    number1, _ := strconv.Atoi(os.Args[1])
    number2, _ := strconv.Atoi(os.Args[2])
    fmt.Println("Sum:", number1+number2)
}

os.Args 변수는 프로그램에 전달되는 모든 명령줄 인수를 포함합니다. 이러한 값은 string 형식이므로 합계를 계산하기 위해 이 값을 int로 변환해야 합니다.

프로그램을 실행하려면 다음 명령을 사용합니다.

go run main.go 3 5

출력은 다음과 같습니다.

Sum: 8

위의 코드를 리팩터링하고 첫 번째 사용자 지정 함수를 만드는 방법을 알아보겠습니다.

사용자 지정 함수

함수를 만드는 구문은 다음과 같습니다.

func name(parameters) (results) {
    body-content
}

func 키워드를 사용하여 함수를 정의한 다음 이름을 할당합니다. 이름 뒤에 함수에 대한 매개 변수 목록을 지정합니다. 0개 이상의 매개 변수가 있을 수 있습니다. 또한 함수의 반환 형식을 정의할 수 있으며, 이것도 0개 이상일 수 있습니다. (다음 섹션에서 여러 값을 반환하는 방법에 관해 설명하겠습니다.) 이러한 모든 값을 정의한 후 함수의 본문 콘텐츠를 작성합니다.

이 기법을 연습하기 위해, 이전 섹션의 코드를 리팩터링하여 사용자 지정 함수에서 숫자를 합산해 보겠습니다. 다음 코드를 사용합니다.

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    sum := sum(os.Args[1], os.Args[2])
    fmt.Println("Sum:", sum)
}

func sum(number1 string, number2 string) int {
    int1, _ := strconv.Atoi(number1)
    int2, _ := strconv.Atoi(number2)
    return int1 + int2
}

이 코드는 두 개의 string 인수를 사용하여 int로 캐스팅한 다음 합산 결과를 반환하는 sum이라는 함수를 만듭니다. 반환 형식을 정의하는 경우 함수는 해당 형식의 값을 반환해야 합니다.

Go에서는 또한 변수인 것처럼 함수의 반환 값에 대한 이름을 설정할 수도 있습니다. 예를 들어 다음과 같이 sum 함수를 리팩터링할 수 있습니다.

func sum(number1 string, number2 string) (result int) {
    int1, _ := strconv.Atoi(number1)
    int2, _ := strconv.Atoi(number2)
    result = int1 + int2
    return
}

이제 함수의 결과 값을 괄호로 묶어야 합니다. 함수 내에서 변수를 사용할 수도 있으며, 그냥 끝에 return 줄을 추가할 수 있습니다. Go는 이러한 반환 변수의 현재 값을 반환합니다. 함수 끝에 return 키워드를 작성하는 것이 편리합니다(특히 반환 값이 둘 이상인 경우). 이 방법은 사용하지 않는 것이 좋습니다. 함수가 반환 하는 것을 명확 하 게 파악할 수 있습니다.

여러 값 반환

Go에서 함수는 두 개 이상의 값을 반환할 수 있습니다. 함수 매개 변수를 정의하는 방법과 비슷한 방식으로 이러한 값을 정의할 수 있습니다. 즉, 형식 및 이름을 지정하지만 이름은 선택 사항입니다.

예를 들어 두 숫자를 합산하기도 하고 곱하기도 하는 함수를 만들려고 합니다. 함수 코드는 다음과 같습니다.

func calc(number1 string, number2 string) (sum int, mul int) {
    int1, _ := strconv.Atoi(number1)
    int2, _ := strconv.Atoi(number2)
    sum = int1 + int2
    mul = int1 * int2
    return
}

이제 함수의 결과를 저장하는 두 개의 변수가 필요합니다. (그렇지 않으면 컴파일되지 않습니다.) 다음과 같습니다.

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    sum, mul := calc(os.Args[1], os.Args[2])
    fmt.Println("Sum:", sum)
    fmt.Println("Mul:", mul)
}

Go의 또 다른 흥미로운 기능은 함수의 반환 값 중 하나가 필요하지 않은 경우 반환 값을 _ 변수에 할당하여 삭제할 수 있다는 것입니다. _ 변수는 Go가 반환 값을 무시하는 자연스러운 방법입니다. 프로그램을 컴파일하도록 허용합니다. 따라서 합계 값만 필요한 경우 다음 코드를 사용할 수 있습니다.

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    sum, _ := calc(os.Args[1], os.Args[2])
    fmt.Println("Sum:", sum)
}

이후 모듈에서 오류 처리를 살펴볼 때, 함수의 반환 값을 무시하는 방법을 자세히 알아보겠습니다.

함수 매개 변수 값 변경(포인터)

함수에 값을 전달하는 경우 해당 함수의 모든 변경 내용이 호출자에게 영향을 주지는 않습니다. Go는 “값으로 전달” 프로그래밍 언어입니다. 함수에 값을 전달할 때마다 Go는 해당 값을 사용 하 고 로컬 복사본 (메모리의 새 변수)을 만듭니다. 함수의 해당 변수에 대한 변경 내용은 함수로 보낸 변수에 영향을 주지 않습니다.

예를 들어 사용자의 이름을 업데이트하는 함수를 만들 수 있습니다. 이 코드를 실행할 때 발생하는 결과를 확인하세요.

package main

import "fmt"

func main() {
    firstName := "John"
    updateName(firstName)
    fmt.Println(firstName)
}

func updateName(name string) {
    name = "David"
}

함수에서 이름을 “David”로 변경한 경우에도 출력은 여전히 “John”입니다. updateName 함수를 변경하면 로컬 복사본만 수정되므로 출력이 변경되지 않았습니다. Go는 변수 자체가 아니라 변수의 값을 전달했습니다.

updateName 함수에서 변경을 수행하여 main 함수의 firstName 변수에 영향을 주려면 포인터를 사용해야 합니다. 포인터는 다른 변수의 메모리 주소를 포함하는 변수입니다. 함수에 포인터를 보낼 때 값을 전달하지 않고 메모리 주소를 전달합니다. 따라서 해당 변수에 대한 모든 변경 내용은 호출자에게 영향을 줍니다.

Go에는 포인터로 작업하는 두 개의 연산자가 있습니다.

  • & 연산자는 뒤에 오는 개체의 주소를 사용합니다.
  • * 연산자는 포인터를 역참조합니다. 이렇게 하면 포인터에 포함된 주소의 개체에 대한 액세스를 제공합니다.

포인터 작동 방식을 설명하는 이전 예제를 수정하겠습니다.

package main

import "fmt"

func main() {
    firstName := "John"
    updateName(&firstName)
    fmt.Println(firstName)
}

func updateName(name *string) {
    *name = "David"
}

위의 코드를 실행합니다. 이제 출력에 John 대신 David가 표시됩니다.

가장 먼저 해야 할 일은 포인터를 받을지 여부를 나타내기 위해 함수의 시그니처를 수정하는 것입니다. 이렇게 하려면 매개 변수 형식을 string에서 *string으로 변경합니다. (후자는 여전히 문자열이지만, 이제 문자열에 대한 포인터입니다.) 그런 다음 해당 변수에 새 값을 할당할 때 변수의 왼쪽에 별표(*)를 추가하여 해당 변수의 값을 생성해야 합니다. updateName 함수를 호출하는 경우 값을 보내지 않고 변수의 메모리 주소를 보냅니다. 변수의 왼쪽에 있는 & 기호는 해당 변수의 주소를 나타냅니다.