함수
- 수학 : 들어가는 변수의 값으로 정해져있는 수식에 대입하여 결과를 도출한다. 입력이 들어가면 결과가 나온다.
- 프로그래밍 : 수학과 의미론적으로는 동일하다. 함수형 언어(functional language)에서는 수학적 의미와 유사하다. 하지만 Go 언어는 함수형 언어가 아니다. Go에서 함수는 코드 블럭이다. 어떠한 기능을 담고 있는 블럭이다.
함수 정의
아래의 예제를 기반으로 함수를 정의하는 방법을 알아보자
func Add( a int, b int) int {
return a + b
}
- 함수 정의 키워드(func) : 중괄호({}) 안의 함수를 정의 하겠다는 키워드
- 함수명(Add) : Add라는 이름의 함수 명을 정의, 함수명은 사용자 임의로 변경이 가능하다. 정의된 함수명으로 외부에서사용하여 해당 함수를 사용할 수 있다.
- 매개변수(a int, b int) : 매개변수는 사용자 임의로 정할 수 있다. 정의된 함수를 호출할 때, 해당 매개변수가 들어가야한다. 함수 내부에서 매개변수를 통해 함수 실행이 진행될 수 있다. 파라미터(parameters), 아규먼트(arguments) 같은 의미다.
- 반환타입(int) : 함수가 반환될 타입을 선언한다
- 함수 코드 블록({ return a+b }) : 중괄호({})안에 실행할 코드를 작성한다. 함수 호출 시, 해당 코드가 실행된다. return이 있다면 결과를 반환한다.
package main
import (
"fmt"
)
func Add(a int, b int) int {
return a + b
}
func main() {
c := Add(3, 6)
fmt.Println(c)
}
Add 함수를 Go 프로그램에 작성하여 실행해보자.
위의 코드를 실행하면 Add 함수가 실행되어 9가 출력된다.
함수 사용 이유
"반복 작업 최소화" 를 목적으로 만들어졌다.
함수 활용
아래의 실행코드를 실행해보자
package main
import "fmt"
func Divide(a, b int) (int, bool) {
if b == 0 {
return 0, false
}
return a / b, true
}
func main() {
c, success := Divide(9, 3)
fmt.Println(c, success)
d, success := Divide(1, 0)
fmt.Println(d, success)
}
반환 값은 여러개로 지정할 수 있다. 반환 값이 여러개일 경우, 괄호(()) 를 활용하면 된다.
재귀 호출(Recursive call)
함수 자기 자신을 호출하는 것을 재귀호출(recursive call)이라고 한다.
재귀 호출은 자기 자신을 호출하고, 호출에서 탈출하는 조건을 작성해주어야 한다.
호출에서 탈출하는 조건이 없을 경우, 그 재귀 함수는 무한으로 실행되어 오류가 발생할 수 있다.
package main
import "fmt"
func printNo(n int){
if n == 0 { //재귀 호출 탈출 조건
return
}
fmt.Println(n)
printNo(n-1)
fmt.Println("After",n)
}
func main(){
printNo(3)
}
해당 재귀호출의 실행 값은 스택(stack)에 쌓인다. Go는 스택의 길이가 자동으로 늘어난다. 메모리가 고갈되지 않는 한, 재귀호출은 계속 실행될 수 있다.
위의 예제에서 printNo(3)을 실행하면 실행될 때마다 남는 변수는 스택에 push 되어진다.
3, fmt.Println(3) |
2, fmt.Println(2) | 3, fmt.Println(3) |
1, fmt.Println(1) | 2, fmt.Println(2) | 3, fmt.Println(3) |
이후 스택에 담긴 값이 순차적으로 실행된다.
결과적으로 위의 코드는 아래와 같이 출력된다.
3
2
1
After 1
After 2
After 3
상수
상수는 값이 변하지 않는 수를 뜻한다.
상수 선언
아래의 예제를 통해 상수를 선언해보자
const ConstValue int = 10
- 상수 선언 키워드(const) : 상수를 선언하는데 붙여주는 키워드이다. 해당 값은 변하지 않는 상수라고 선언한다. 키워드가 없으면 변할 수 있는 변수가 된다. const는 constant의 약자이다.
- 상수명(constvalue) : 사용할 상수의 명칭이다.
package main
import "fmt"
func main(){
const pi1 float64 = 3.141592653589793228 //상수
var pi2 float64 = 3.141592653589793228 //변수
pi1 = 3 //상수는 변할 수 없으므로, 해당 값에서 오류가 난다.
pi2 = 4
fmt.Printf("원주율 : %f\n",pi1)
fmt.Printf("원주율 : %f\n",pi2)
}
위의 예제는 실행을 할 수 없다. 상수는 변할 수 없으므로, 코드는 오류가 난다.
상수 사용 이유
코드 값으로 사용
코드란 숫자에 의미를 부여하는 것이다. 상수는 주로 코드값으로 사용한다. 대표적으로 ASCII 코드가 있다.
package main
import "fmt"
const Pig int = 0
const Cow int = 1
const Chicken int = 2
func main() {
PrintAnimal(0)
PrintAnimal(1)
PrintAnimal(2)
}
func PrintAnimal(animal int) {
if animal == Pig {
fmt.Println("꿀꿀")
} else if animal == Cow {
fmt.Println("음메")
} else {
fmt.Println("꼬끼오")
}
}
iota로 열거값 사용
단순한 열거형 값은 iota 를 사용하여 쉽게 생성할 수 있다.
//iota1
const (
Red int = iota //0
Blue int = iota //1
Green int = iota //2
)
//iota2
const (
C uint = iota + 1 //1 = 0+1
C2 //2 = 0+2
C3 //3 = 0+3
)
iota를 응용 하여 비트 플래그를 쓰기도 한다.
const(
BitFlag1 uint = 1<< iota //1 = 1 << 0 -> 0000 0001
BitFlag2 //2 = 1 << 1 -> 0000 0010
BitFlag3 //4 = 1 << 2 -> 0000 0100
BitFlag4 //8 = 1 << 3 -> 0000 1000
)
위와 같이 사용할 수 있다.
비트플래그 활용 예제
package main
import "fmt"
const (
MasterRoom uint8 = 1 << iota
LivingRoom
BathRoom
SmallRoom
)
func SetLight(rooms, room uint8) uint8 {
return rooms | room
}
func ResetLight(rooms, room uint8) uint8 {
//bit clear
return room &^ room
}
func IsLightOn(rooms, room uint8) bool {
return rooms&room == room
}
func TurnLights(rooms uint8) {
if IsLightOn(rooms, MasterRoom) {
fmt.Println("안방에 불을 켠다")
}
if IsLightOn(rooms, LivingRoom) {
fmt.Println("거실에 불을 켠다")
}
if IsLightOn(rooms, BathRoom) {
fmt.Println("화장실에 불을 켠다")
}
if IsLightOn(rooms, SmallRoom) {
fmt.Println("작은방에 불을 켠다")
}
}
//bit 단위로 의미를 부여할 수 있다.
func main() {
var rooms uint8 = 0 //모든 bit 0
rooms = SetLight(rooms, MasterRoom) //0000 0001
rooms = SetLight(rooms, LivingRoom) //0000 0010
rooms = SetLight(rooms, BathRoom) //0000 0100
rooms = SetLight(rooms, SmallRoom) //0000 1000
rooms = ResetLight(rooms, MasterRoom)
TurnLights(rooms)
}
타입이 없는 상수
상수는 타입이 없이 선언될 수 있다. 타입 없이 선언된 상수는 활용될때 타입이 선언된다.
package main
import "fmt"
const PI = 3.14 //타입이 없는 상수
const FloatPI float64 = 3.14
func main() {
var a int = PI * 100 //타입 오류 미발생
var b int = FloatPI * 100 //타입 오류 발생
fmt.Println(a)
fmt.Println(b)
}
상수 깊이 보기
- 상수는 좌변으로 사용할 수 없다.
상수는 메모리 공간으로 사용할 수 없고, 값 으로만 사용할 수 있다.
상수는 동적 메모리 공간을 차지하지 않고, 코드에 정적으로 할당된 값이다. 즉 런타임 중에 변경될 수 없다.
참고
Tucker의 Go언어 프로그래밍 - Go가 온당 7장, 8장
https://www.youtube.com/c/TuckerProgramming/videos
'Programming Language > go' 카테고리의 다른 글
Go 언어 프로그래밍 - 조건문과 반복문 (배열) (0) | 2021.07.12 |
---|---|
Go 언어 프로그래밍 - 조건문과 반복문 (if문, switch문, for문) (0) | 2021.07.10 |
Go 언어 프로그래밍 - 슬라이스(Slice) (0) | 2021.07.05 |
Go 언어 프로그래밍 - 연산자 (0) | 2021.07.05 |
Go 언어 프로그래밍 - fmt 패키지를 이용한 표준 입출력 (0) | 2021.07.05 |