안녕하세요, 주니어 개발자 Eon입니다.
이번 포스트에서는 함수에 대해서 다루겠습니다.
함수는 수학에서 f(x) 로 표현합니다.
그리고 함수 f(x)는 어떠한 수식을 담고 있습니다.
f(x) = x + 5
f(3) = 3 + 5 = 8
이렇게 표현하곤 합니다.
컴퓨터에서의 함수는 언어마다 사용하는 방법만 조금 다를 뿐, 수학에서의 함수와 다를 바 없습니다.
입력값에 대한 출력값, 이게 함수입니다.
f(x)라는 함수에 입력값 3를 넣어, 함수의 동작으로 5를 더한 뒤, 출력값 8이 반환되었습니다.
컴퓨터에서의 함수 또한 입력값과 반환값으로 되어 있고, 이를 사용해 프로그램을 구성합니다.
Golang에서 변수나 함수의 이름을 작성하는 방법은 정해져 있어, 매우 쉬운 편입니다.
(그저 이름을 뭐로 지을지가 고민일뿐..)
현재 패키지 외부에서도 쓰일 수 있게 하려면 대문자로, [Unicode upper case letter (Unicode class "Lu");]
현재 패키지 내부에서만 쓰일 수 있게 하려면 그 외의 문자로 시작하면 됩니다.
이는 사용자 간의 약속이 아닌 Golang 자체적 기능으로 분류된 것입니다.
영대문자가 아닌 문자로 선언된 변수나 함수는 전부 외부 패키지에서 다룰 수 없습니다.
go.dev/ref/spec#Exported_identifiers
Golang은 기본 인코딩이 UTF-8입니다.
따라서, 한글로 된 이름도 선언이 가능합니다.
UTF-8 문자로 패키지 외부에서 사용할 수 있게 하려면 반드시 문자 앞에 영대문자를 붙여주어야 합니다.
"한글함수" => "A한글함수"
"한글변수" => "A한글변수"
Golang에서의 함수는 다음과 같이 사용할 수 있습니다.
func NameOfFunc(a int, b int) (isTrue bool) { isTrue = (a == b) return }
- func : function(함수)의 약자로, 함수를 정의할 때 꼭 포함해야 함
- NameOfFunction : 함수의 이름이며, 영대문자로 시작하기 때문에 외부 패키지에서도 사용이 가능함
- (a int, b int) : 함수 내에서 사용될 매개변수 a와 b를 각각 int로 선언함
- (isTrue bool) : 함수의 반환값을 변수 isTrue로 하며, 해당 변수는 bool 타입임
- { ... } : 함수의 내용을 적는 파트이며, 자유롭게 작성함
- isTrue = (a == b) : 비교 연산자 '=='으로 변수 a와 b가 동일한지 체크함
- a == b 가 참일 때는 true, 거짓일 때는 false를 반환함
- return : 값을 반환함 -> 반환할 값을 변수 isTrue로 지정했기 때문에 변수명을 적지 않아도 됨
아래는 같은 기능을 하는 함수를 다르게 표현함
func nameOfFunc(a, b int) bool { isTrue := (a == b) return isTrue }
- nameOfFunc : 함수 이름이며, Lu class 문자가 아니기 때문에 외부 패키지에서 불러올 수 없음
- (a, b int) : 변수 a와 b 모두 int타입이라, 한 번에 선언함
- bool : 반환값의 타입만 명시하고 반환할 값은 지정하지 않음
- isTrue := (a == b) : isTrue 변수를 (a == b) 결과값에 맞는 타입으로 선언함
- return isTrue : bool 타입 변수인 isTrue를 반환함
참고 : Golang에는 삼항 연산자가 없다. return (a == b) ? true : false 를 하고 싶으나, Golang에서는 불가하다.
go.dev/doc/faq#Does_Go_have_a_ternary_form
Golang에서 함수를 사용하는 방법은 다음과 같습니다.
프로젝트에서 위와 같이 직접 작성하거나, 외부 패키지를 임포트하여 해당 패키지의 함수를 사용할 수 있습니다.
아래는 main 함수에서 위에 작성한 함수를 사용하는 방법입니다.
package main import "fmt" func nameOfFunc(a, b int) bool { isTrue := (a == b) return isTrue } func main() { isOk := nameOfFunc(3, 5) fmt.Println(isOk) }
- package main : main 패키지이며, 해당 프로그램의 진입 패키지임
- import "fmt" : 아래 main 함수에서 결과값 출력을 위해 import함
- func main() { ... } : main 함수는 매개변수와 반환값이 없어야 함; 프로그램 실행 시, 가장 먼저 실행되는 함수라서 어떠한 매개변수도 전달받지 않으며, main 함수의 내용이 순차적으로 실행되고 main 함수가 모두 실행되면 프로그램이 종료됨
- isOk := nameOfFunc(3, 5) : isOk라는 변수를 선언하며 값으로는 nameOfFunc(3, 5)의 반환값을 넣음
- nameOfFunc(3, 5) : nameOfFunc() 함수에 매개변수 3과 5를 전달하며, 이는 각각 위의 nameOfFunc() 함수의 변수 a와 b로 사용됨
이렇게 여러 가지 기능을 함수로 구현하고, 그 기능들을 복합적으로 활용하여 프로그램이 만들어집니다.
recursive function은 재귀함수라고 합니다.
함수 자기 자신이 자기 자신을 다시 호출하는 방식입니다.
이 방식은 call stack이 많이 쌓일 수 있어서 그리 선호되는 방식은 아닙니다.
위 그림과 같이 main()에서 recursiveAddFunc()를 호출하고, 그 안에서 다시 recursiveAddFunc()을 호출하고, 그 안에서 ...
이렇게 반복되다가 탈출 조건을 만나고, 값을 return할 때,
한 번에 해당 값이 main()으로 반환되는 것이 아니라 콜스택 가장 위에 있는 함수에서 이전 함수로 반환하고, 그리고 또 이전 함수로 반환하고, 그리고 또 이전 ...
결국 최종적으로 얻고 싶었던 값조차 재귀함수가 호출된 횟수만큼 return을 거쳐야 하기 때문에 비효율적입니다.
가급적 반복적인 기능 수행이 필요한 경우에는 반복문을 통해서 수행하고, 재귀함수는 꼭 필요한 때에만 사용하도록 하는 게 좋습니다.
Golang에서 재귀함수는 다음과 같이 구현할 수 있습니다.
package main import "fmt" func recursiveAddFunc(a, b int) int { a += b if a < 100 { fmt.Println("Before recursive call, a is :", a) a = recursiveAddFunc(a, b) fmt.Println("After recursive call, a is :", a) } return a } func main() { fmt.Println(recursiveAddFunc(5, 3)) }
- a += b : a에 b를 더한 값을 a에 대입함
- if a < 100 { ... } : a가 100보다 작을 때, 조건문 내의 내용을 수행함; 이 코드의 재귀함수 탈출 조건으로 사용되었으며, a가 100보다 커지면 if 조건문을 넘어가서 return a 를 수행함
(추후 다른 포스트에서 다룰 내용임)- a = recursiveAddFunc(a, b) : 재귀함수 호출을 하고, 반환값을 a에 대입함
- func main() { fmt.Println(recursiveAddFunc(5, 3)) } : recursiveAddFunc(5, 3)의 반환값을 출력함
위의 코드 실행으로, 재귀함수 동작을 이해하기 좋습니다.
아래는 Golang으로 만든 간단한 사칙연산 계산기 프로그램입니다.
아직 조건문에 대한 내용을 다루지 않아 함수로만 구현하였고, 한 번에 모든 연산에 대한 결과를 출력하는 프로그램입니다.
package main import "fmt" func addFunc(a, b int) int { return a + b } func subFunc(a, b int) int { return a - b } func mulFunc(a, b int) int { return a * b } func divFunc(a, b int) int { return a / b } func modFunc(a, b int) int { return a % b } func main() { var x, y int fmt.Println("write two values to calculate..") fmt.Println("format : 'value1 value2' then 'press Enter'") fmt.Scanf("%d %d", &x, &y) fmt.Println("result of addFunc(x, y) is :", addFunc(x, y)) fmt.Println("result of subFunc(x, y) is :", subFunc(x, y)) fmt.Println("result of mulFunc(x, y) is :", mulFunc(x, y)) fmt.Println("result of divFunc(x, y) is :", divFunc(x, y)) fmt.Println("result of modFunc(x, y) is :", modFunc(x, y)) }
실행 후, 연산을 수행할 값 두 개를 입력하면 결과가 출력됩니다.
이번 포스트는 함수에 대한 내용이었습니다.
Go도 익명함수가 있습니다. 다만 나중에 다루도록 하겠습니다.
감사합니다.👍