네 개의 형태로 나눌 수 있습니다.
/*기능들만 모아놓은 함수들*/
func guide() { //매개변수 X 반환 값 X
fmt.Println("두 정수를 입력받고 곱한 결과를 출력하는 프로그램입니다.\n두 정수를 차례로 띄어 써주세요.")
fmt.Print("두 정수를 입력해주세요 :")
}
func input() (int, int) { //매개변수 X 반환 값 O(두 개)
var a, b int
fmt.Scanln(&a, &b)
return a, b
}
func multi(a, b int) int { //매개변수 O, 반환 값 O
return a * b
}
func printResult(num int) { //매개변수 O, 반환 값 X
fmt.Printf("결과값은 %d입니다. 프로그램을 종료합니다.\n", num)
}
Pass by value 일반적인거 (다른언어와 동일)
package main
import "fmt"
func printSqure(a int) {
a *= a
fmt.Println(a)
}
func main() {
a := 4 //지역변수 선언
printSqure(a)
fmt.Println(a)
}
Go 는 포인터를 지원하기 때문에 Pass by reference
package main
import "fmt"
func printSqure(a *int) {
*a *= *a
fmt.Println(*a)
}
func main() {
a := 4 //지역변수 선언
printSqure(&a) //참조를 위한 a의 주솟값을 매개변수로 전달
fmt.Println(a)
}
package main
import "fmt"
func addOne(num ...int) int {
var result int
for i := 0; i < len(num); i++ { //for문을 이용한 num[i] 순차 접근
result += num[i]
}
return result
}
func addTwo(num ...int) int {
var result int
for _, val := range num { //for range문을 이용한 num의 value 순차 접근
result += val
}
return result
}
func main() {
num1, num2, num3, num4, num5 := 1, 2, 3, 4, 5
nums := []int{10, 20, 30, 40}
fmt.Println(addOne(num1, num2))
fmt.Println(addOne(num1, num2, num4))
fmt.Println(addOne(nums...))
fmt.Println(addTwo(num3, num4, num5))
fmt.Println(addTwo(num1, num3, num4, num5))
fmt.Println(addTwo(nums...))
}
Go 언어에서는 복수개의 반환값을 반환할 수 있다는 것입니다.
반환값는 수 만큼 반환타입을 모두 명시해야합니다.
package main
import "fmt"
func add(num ...int) (int, int) {
var result int
var count int
for i := 0; i < len(num); i++ { //for문을 이용한 num[i] 순차 접근
result += num[i]
count++
}
return result, count
}
func main() {
nums := []int{10, 20, 30, 40, 50}
fmt.Println(add(nums...))
}
반환 타입만 적었는데, 변수명과 타입을 같이 적어주는 기법입니다.
따로 선언할 필요 없습니다.
return은 생략하면 안됩니다.
func dessertList(fruit ...string) (count int, list []string) { //여기서 이미 선언된 것이다
...
return //생략하면 안 된다
}
익명 함수는 좀 독특합니다.
package main
import "fmt"
func main() {
func() {
fmt.Println("hello")
}()
func(a int, b int) {
result := a + b
fmt.Println(result)
}(1, 3)
result := func(a string, b string) string {
return a + b
}("hello", " world!")
fmt.Println(result)
i, j := 10.2, 20.4
divide := func(a float64, b float64) float64 {
return i / j
}(i, j)
fmt.Println(divide)
}
보면 선언과 동시에 실행하고 있습니다.
저 위에서 함수 반환값과 이름을 선언해서 변수처럼 사용하고 return 만하는 Named Return Parameter 를 배웠는데 익명함수에서도 비슷한 기능이 있습니다.
다만 변수에 초기화한 익명 함수는 변수 이름을 함수의 이름처럼 사용할 수 있다는 것 입니다.
addAnonymous := func(nums ...int) (result int) {
for i := 0; i < len(nums); i++ {
result += nums[i]
}
return
}
이렇게 사용합니다. 근데 결국 선언함수와 똑같아지는데..흠..
선언함수와 익명함수는 프로그램 내부적으로 읽는 순서가 다릅니다. 선언함수는 프로그램이 시작됨과 동시에 모두 읽습니다. 하지만 익명 함수는 위 예시들처럼 그 자리에서 실행되기 때문에 해당 함수가 실행되는 곳에서 읽습니다. 즉, 선언함수보다 익명 함수가 나중에 읽힙니다. 그래서 만약 선언함수와 익명함수가 이름이 같으면 익명함수가 선언함수를 덮어씁니다. 지역변수와 전역변수의 차이점과 같습니다.
package main
import "fmt"
func add() {
fmt.Println("선언 함수를 호출했습니다.")
}
func main() {
add := func() {
fmt.Println("익명 함수를 호출했습니다.")
}
add()
}
익명 함수의 사용은 Go언어에서 함수가 '일급 함수' 이기 때문에 가능한 것입니다.
함수는 다른 타입들과 비교했을 때 높은 수준의 용법이 아니라 같은 객체로서 사용될 수 있습니다.
함수자체를 인자로 넘길 수 있습니다. (아래 코드 확인)
package main
import "fmt"
// 3. 그럼 매개변수에 다 적어줘야함 (<- 귀찮)
func calc(f func(int, int) int, a int, b int) int {
result := f(a, b)
return result
}
func main() {
// 1. 멀티라는 함수를 만들고
multi := func(i int, j int) int {
return i * j
}
// 2. calc 함수로 넘김
r1 := calc(multi, 10, 20)
fmt.Println(r1)
}
위에 코드에서 3.번을 보면 가독성도 떨어지고 번거롭다는 것을 알수 있습니다.
그래서 'type' 문을 사용해 함수의 원형을 정의하고 사용자가 정의한 이름을 사용합니다.
c 의 구조체 개념과 유사합니다. (구조체 이름 만들고 .. 그랬던 기억이..)
//1. 함수 원형 정의
type calculatorNum func(int, int) int
// 4. 함수 선언에 함수 원형정의가 되어있어서 가독성이 좋아졌습니다.
func calNum(f calculatorNum, a int, b int) int {
result := f(a, b)
return result
}
func main() {
// 2. 익명함수, 맨위에 함수원형 정의가 되어있습니다.
multi := func(i int, j int) int {
return i * j
}
// 3. 넘깁니다.
r1 := calNum(multi, 10, 20)
fmt.Println(r1)
}