로즈마리

글 작성자: daily_zi

Go에서 함수는 func 키워드를 사용하여 정의한다.

func 뒤에 함수명을 적고 괄호 ( ) 안에 그 함수에 전달하는 파라미터들을 적게 된다. 함수 파라미터는 0개 이상 사용할 수 있는데, 각 파라미터는 파라미터명 뒤에 int, string 등의 파라미터 타입을 적어서 정의한다. 함수의 리턴 타입은 파라미터 괄호 ( ) 뒤에 적게 된다.

 

간다한게 함수를 정의하고 호출해보자.

단, Go 언어를 함수를 정의했을 때,  시작한 줄에서 { (여는 중괄호)를 다음 줄에 작성하면 컴파일 에러가 발생한다.

  • func  함수명() {}
package main
func main() {
    msg := "Hello, World!"
    say(msg)
}
 
func say(msg string) {
    println(msg) //Hello, World! 출력 
}

위 예제는 say라는 함수를 정의한 예이다. say() 함수는 문자열 msg 파라미터를 하나 갖고 있으며, 리턴 값이 없으므로 별도의 리턴타입을 정의하지 않았다.


_Pass By Value & Pass By Reference

Go에서 파라미터를 전달하는 방식은 크게 Pass By Value와 Pass By Reference로 나뉜다.

  1. Pass By Value
    위 예제에서는 msg의 값 "Hello, World!" 문자열이 복사되어 함수 say()에 전달된다. 즉, 만약 파라미터 msg의 값이 say() 함수 내에서 변경된다하더라도 호출함수 main()에서의 msg 변수는 변함이 없다.
  2. Pass By Reference
    아래의 예제에서처럼 msg 변수앞에 & 부호를 붙이면 msg 변수의 주소를 표시하게 된다. 흔히 포인터라 불리우는 이 용법을 사용하면 함수에 msg 변수의 값을 복사하지 않고 msg 변수의 주소를 전달하게 된다. 피호출 함수 say()에서는 *string 과 같이 파라미터가 포인터임을 표시하고 이때 say 함수의 msg는 문자열이 아니라 문자열을 갖는 메모리 영역의 주소를 갖게 된다. msg 주소에 데이타를 쓰기 위해서는 *msg = "" 과 같이 앞에 *를 붙이는데 이를 흔히 Dereferencing 이라 한다.
package main
func main() {
    msg := "Hello, World!"
    say(&msg)
    println(msg) //변경된 메시지 출력, Changed!
}
 
func say(msg *string) {
    println(*msg) //Hello, World!
    *msg = "Changed" //메시지 변경
}

_Variadic Function (가변인자함수)

함수에 고정된 수의 파라미터들을 전달하지 않고 다양한 숫자의 파라미터를 전달하고자 할 때 가변 파라미터를 나타내는 ... 을 사용한다.  즉 문자열 가변 파라미터를 나타내기 위해서 ...int 또는 ...string 과 같이 표현하며  n개의 동일타입 파라미터를 전달할 수 있다. 

 

package main
func main() {   
    sayInt(10, 20, 30, 40)
    sayString("Hello, World!")
}

func sayInt(msg ...int) {
    for _, i := range msg {
        println(i) //10, 20, 30, 40
    }
}
 
func sayString(msg ...string) {
    for index, s := range msg {
        println(index, s) //Hello, World!
    }
}

_함수 리턴 값

Go 프로그래밍 언어에서 함수는 리턴값이 없을 수도, 리턴값이 하나 일 수도, 또는 리턴값이  n개일 수도 있다.

Go 언어는 또한 리턴되는 값들을 (함수에 정의된) 리턴 파라미터들에 할당할 수 있는 'Named Return Parameter' 라는 기능을 제공한다.

 

함수에서 리턴 값이 있는 경우는 func() 다음에 리턴값의 타입을 정의한다. 그리고 값을 리턴하기 위해 함수내에서 return 키워드를 사용한다. 예를 들어, 아래 예제는 sum() 함수의 리턴 타입이 int 임을 표시하고 있으며, sum 함수 마지막에 return s 와 같이 정수 s의 값을 리턴하고 있다.

package main
func main() {
    total := sum(1, 3, 5, 7, 9)
    println(total)
}
 
func sum(nums ...int) int {
    s := 0
    for _, n := range nums {
        s += n
    }
    return s
}

Go에서는 복수 개의 값을 리턴하기 위해서는 해당 리턴 타입들을 괄호 ( ) 안에 적어 준다. 예를 들어, 처음 리턴값이 int이고 두번째 리턴값이 string 인 경우 (int, string) 과 같이 적어 준다.

package main
func main() {
    count, total := sum(1, 3, 5, 7, 9)
    println(count, total)   
}
 
func sum(nums ...int) (int, int) {
    sum := 0      // 합계
    count := 0  // 요소 갯수
    for _, n := range nums {
        sum += n
        count++
    }
    return count, sum
}

Go에서 Named Return Parameter들에 리턴값들을 할당하여 리턴할 수 있는데, 이는 리턴되는 값들이 여러 개일 때, 코드 가독성을 높이는 장점이 있다.

아래 예제에서 func 라인의 마지막 리턴타입 정의 부분을 보면, (int, int) 가 아니라 (count int, total int) 처럼 정의되어 있음을 볼 수 있다. 즉, 리턴 파라미터명과 그 타입을 함께 정의한 것이다. 그리고 함수 내에서는 이 count, total에 결과값을 직접 할당하고 있음을 볼 수 있다. 또한 마지막에 return 문이 있는 것을 볼 수 있는데, 실제 return 문에는 아무 값들을 리턴하지 않지만, 그래도 리턴되는 값이 있을 경우에는 빈 return 문을 반드시 써 주어야 한다 (이를 생략하면 에러 발생).

package main

func main(){
    count, total := sum(1,3,5,7,9)
    println(count, total)
}

func sum(nums ...int) (count int, total int) {
    for _, n := range nums {
        total += n
    }
    count = len(nums)
    return
}

_함수를 변수에 저장

var 변수명 func(매개변수명 자료형) 리턴값_자료형 = 함수명

함수를 정의한 뒤 미리 선언한 변수에 대입하기만 하면 함수를 변수에 저장할 수 있다.

package main

func sum(a int, b int) int {
	return a - b
}


func main() {
	var cal func(a int, b int) int = sum   // 함수를 저장하는 변수를 선언하고 함수 대입
	result := sum                          // 변수 선언과 동시에 함수를 바로 대입

	println(   cal(20, 10)) // 10: cal    변수에 저장된 sum 함수 호출
	println(result(30, 10)) // 20: result 변수에 저장된 sum 함수 호출
}

 

'프로젝트 > go' 카테고리의 다른 글

Go 언어 입문_Method(메소드)  (0) 2019.09.09
Go 언어 입문_Struct(구조체)*  (0) 2019.09.06
Go 언어 입문_변수  (0) 2019.09.02
Go 언어 입문  (1) 2019.09.02
jteeuwen/go-bindata  (0) 2019.06.24