다른 어떤 언어들 처럼 자주 사용되는 코드를 묶어서 함수를 만든다. 그러면 같은 기능을 매번 다시 만들 필요 없이 재사용할 수 있다.
함수란 특별한 목적의 작업을 수행하는 코드 묶음이다. 일정 범위의 코드를 묶어서 함수를 만들면 같은 코드를 여러 번 작성하지 않고 한 번만 작성해 재활용할 수 있다.
함수는 함수 키워드, 함수명, 매개변수, 반환 타입, 함수 코드 블록으로 구성된다.

func 함수 정의를 알림{가 함수를 정의하는 라인과 항상 같은줄에 있어야 함함수명과 변수명 명명 규칙 :
첫 글자가 대문자인 함수는 패키지 외부로 공개되는 함수
package main
import "fmt"
func Add(a int, b int) int {
return a + b
}
func main() {
c := Add(3,6)
fmt.Println(c)
}
함수를 호출할때 입력값으로 쓰인 인자는 그대로 사용되는 것이 아니라 값이 복사되어 사용된다.
다음과 같이 Add()함수를 호출할 때 인수가 매개변수에 복사되어 전달된다.
package main
import "fmt"
func Add(a int, b int) int { // 2️⃣ 매개변수 생성 및 초기화
return a + b // 3️⃣ 값 반환 (복사)
}
func main() {
c := Add(3,6) // 1️⃣ 함수 호출
fmt.Println(c)
}
1️⃣ Add()함수를 호출한다.
2️⃣ 매개변수를 선언하고 입력한 인수의 값을 복사한다. 여기서는 3과 6이 a와 b에 값으로 복사된다.
3️⃣ return 키워드를 사용해서 함수 결과가 반환된다.
package main
import "fmt"
func Add(a int, b int) int {
return a + b
} // 5️⃣ 로컬 변수 삭제
func main() {
c := Add(3,6) // 4️⃣ 복사
fmt.Println(c)
}
4️⃣ 반환된 값은 함수가 호출된 곳을 대체하는 것과 같다.
5️⃣ 호출한 함수가 종료되면 함수에서 사용한 지역변수에 접근할 수 없다. return으로 함수 결과가 반환되면서 함수가 즉시 종료되어 함수를 호출했던 호출 위치로 명령 포인터가 되돌아가서 수행된다.
명령 포인터 (Instruction Pointer) :
명령 포인터 혹은 프로그램 카운터로 불리는 것으로, 다음 명령을 수행할 위치를 나타내는 내부 레지스터
package main
import "fmt"
func Add(a int, b int) int {
return a + b
}
func main() {
c := Add(3,6) // 6️⃣ 대입 연산
fmt.Println(c) // 9
}
6️⃣ c에 반환값(9)이 대입(복사)된다.
"인수는 매개변수로 복사"된다는 뜻은, "매개변수와 함수 내에서 선언된 변수는 함수가 종료되면 변수 범위를 벗어나서 접근하지 못한다"와 같은말이다.
함수를 쓰면 반복 사용되는 코드를 묶을 수 있다. 함수를 이용해서 중복 코드를 제거하여 코드를 간결하게 만들어 가독성을 높일 수 있고 유지보수 또한 용이해진다.
다음의 코드는 수학, 영어, 역사 시험 성적의 평균 점수를 출력하는 예제이다.
package main
import "fmt"
func main() {
math := 80
eng := 74
history := 95
fmt.Println("A의 평균 점수는", (math + eng + history) / 3, "입니다.")
math := 88
eng := 92
history := 53
fmt.Println("B의 평균 점수는", (math + eng + history) / 3, "입니다.")
math := 78
eng := 73
history := 78
fmt.Println("C의 평균 점수는", (math + eng + history) / 3, "입니다.")
}
이 예제의 문제점 :
각 변수에 점수를 입력하는 코드와 점수를 출력하는 코드가 학생 수 만큼 반복되었다.
package main
import "fmt"
func PrintAvgScore(name string, math int, eng int, history int) {
total := math + eng + history
avg := total / 3
fmt.Println(name, "의 평균 점수는", avg, "입니다.")
}
func main() {
PrintAvgScore("A", 80, 74, 95) //A의 평균 점수는 83입니다.
PrintAvgScore("B", 88, 92, 53) //B의 평균 점수는 77입니다.
PrintAvgScore("C", 78, 73, 78) //C의 평균 점수는 76입니다.
}
함수 사용 후 :
4줄의 코드가 1줄의 코드 입력으로 바뀌었다.
코드의 파악이 쉽고 추후 유지 보수도 용이하다.
함수는 값을 여러 개 반환할 수 있는데, 반환값이 여러개 일 때는 반환 타입들을 소괄호로 묶어서 표현한다.
package main
import "fmt"
func Divide(a, b int) (int, bool) { // 1️⃣ 함수 선언
if b == 0 {
return 0, false // 2️⃣ 제수가 0일 때 반환
}
return a / b, true // 3️⃣ 제수가 0이 아닐 때 반환
}
func main() {
c, success := Divide(9, 3) // 4️⃣ 제수가 0이 아닌 경우
fmt.Println(c, success) // 3 true
d, success := Divide(9, 0) // 5️⃣ 제수가 0인 경우
fmt.Println(d, success) // 0 false
}
1️⃣ 함수를 정의한다. 이 함수는 int 타입 a,b를 매개변수로 받고 int 타입과 bool타입을 반환한다.
2️⃣ 나눗셈 제수가 0이면 false를 반환
3️⃣ 나눗셈 제수가 0이 아니면 나눗셈 결과와 true를 반환
4️⃣,5️⃣ Divide()함수를 호출하고, 그 결과를 변수 c와 success로 받는다. 첫 번째 반환값은 c, 두 번째 반환값은 success에 대입
함수 선언부에 반환 타입을 적을 때 변수명까지 지정해주면, return문으로 해당 변수를 명시적으로 반환하지 않아도 값을 반환할 수 있다.
package main
import "fmt"
func Divide(a, b int) (result int, success bool) { // 1️⃣ 반환할 변수명 명시
if b == 0 {
result = 0
success = false
return // 2️⃣ 명시적으로 반환할 값을 지정하지 않은 return문
}
result = a / b,
success = true
return
}
func main() {
c, success := Divide(9, 3)
fmt.Println(c, success) //3 true
d, success := Divide(9, 0)
fmt.Println(d, success) //0 false
}
1️⃣ 첫 번째 반환할 변수로 result, 두 번째 반환할 변수 success로 지정. 지정된 result, success는 함수 내부에서 변수로 동작
2️⃣ 함수 결과를 반환할 때 명시적으로 result, success를 지정하지 않았지만 두 값이 반환
📍 변환할 변수에 이름을 지정할 경우 모든 반환 변수에 이름을 지정하거나 모두 지정하지 않거나 해야함
재귀 호출 : 함수안에서 자기 자신 함수를 다시 호출하는 것
package main
import "fmt"
func printNo(n int) {
if n == 0 { // 2️⃣ 재귀 호출 탈출 조건
return
}
fmt.Println(n)
printNo(n-1) // 3️⃣ 재귀 호출
fmt.Println("After", n) // 4️⃣ 재귀 호출 이후 출력
}
func main() {
printNo(3) // 1️⃣ 함수 호출
}
/*
결과값
3
2
1
After 1
After 2
After 3
*/
1️⃣ printNo() 함수를 호출
2️⃣ 탈출 조건인지 확인. n이 0이 아니면
3️⃣ printNo() 함수 재호출
호출 순서를 보면 printNo(3)이 먼저 호출되고 이어서 printNo(2), printNo(1), printNo(0) 순으로 호출된다. 최종적으로 printNo(0)이 호출 됐을 때 2️⃣의 탈출 조건을 만족해 return되어 종료되고, 재귀 호출된 printNo() 함수가 종료되면 호출자인 printNo()의 4️⃣의 위치로 반환되고 거기에서 명령을 수행해서 "After" 메시지가 출력

위 그림처럼 printNo() 함수 내에서 printNo(n-1)을 호출하면, main() 함수에서 printNo(3)을 호출한 뒤 printNo(2), printNo(1), printNo(0)을 차례로 호출한다. printNo(0)에서는 재귀 호출 탈출 조건 (n ==0)을 만족하므로 자신을 호출한 위치로 차례대로 연속해서 돌아가게 되어 최종적으로 최초 호출했던 main()함수 위치로 되돌아간다.
재귀 호출을 사용할 때는 항상 탈출 조건을 정해야 하는데, 앞 예제의 1️⃣처럼 재귀 호출이 종료되는 시점을 명확하게 하지 않으면 무한루프에 빠짐