함수는 값이다.
- 함수를 값으로 사용하여 함수를 맵의 값으로 사용해 계산기를 만드는 예제
func add(i, j int) int {
return i+j
}
func sub(i, j int) int {
return i-j
}
func mul(i, j int) int {
return i*j
}
func div(i, j int) int {
return i/j
}
func main() {
var opMap = map[string]func(int, int) int{
"+": add,
"-": sub,
"*": mul,
"/": div,
}
expressions := [][]string{
[]string{"2", "+", "3"},
[]string{"2", "*", "-3"},
}
for _, expression := range expressions {
if len(expression) != 3 {
return
}
op := expression[1]
opFunc, ok := opMap[op]
if !ok {
continue
}
p1, err := strconv.Atoi(expression[0])
if err != nil {
return
}
p2, err := strconv.Atoi(expression[0])
if err != nil {
return
}
result := opFunc(p1, p2)
fmt.Println("result is ", result)
}
}
함수 타입 선언에도 type 을 사용할 수 있다.
type opFuncType func(int, int) int
- 위와 같이 선언하면, 다음처럼 수정할 수 있다.
var opMap = map[string]opFuncType{
"+": add,
"-": sub,
"*": mul,
"/": div,
}
익명 함수
- 함수 내에 새로운 함수를 정의하여 변수에 할당할 수 있다.
- 주로
defer
문과goroutine
에서 익명 함수를 사용한다.
for i := 0; i < 5; i++ {
func(j int) {
fmt.Println(j)
} (i)
}
클로저
- 함수 내부에 선언된 함수로, 클로저는 외부 함수에서 선언한 변수를 접근하고 수정할 수 있는것을 의미한다.
- 함수는 값이고, 파라미터와 반환값을 사용하여 함수의 타입을 지정할 수 있기 때문에, 파라미터로 함수를 다른 함수로 넘길 수 있다.
- 파라미터로 함수를 전달
func Slice(x any, less func(i, j int) bool)
- 클로저 함수에서 people 변수를 사용하여 Age 오름차순으로 정렬
people := []Person{
{"Atom", "Patterson", 10},
{"Bryan", "Lee", 15},
{"Catty", "Brace", 20},
}
sort.Slice(people, func(i int, j int) bool {
return people[i].Age < people[j].Age
})
fmt.Printf("%+v", people)
// [{FirstName:Atom LastName:Patterson Age:10} {FirstName:Bryan LastName:Lee Age:15} {FirstName:Catty LastName:Brace Age:20}]
- 함수에서 함수 반환
func makeMult(base int) func(int) int {
return func(factor int) int {
return base * factor // 클로저를 반환
}
}
func main() {
twoBase := makeMult(2)
threeBase := makeMult(3)
for i := 0; i < 3; i++ {
fmt.Println(twoBase(i), threeBase(i))
}
}
// 0 0
// 2 3
// 4 6
- 함수에서 클로저를 반환할 수 있다.
- 클로저 반환의 경우,
미들웨어
나defer
에서 사용되는 것을 확인할 수 있다.
- 클로저를 사용하면 지역 변수가 소멸되지 않고, 나중에 함수를 호출할 때마다 계속 가져다 쓸 수 있다.
i := 10
는 클로저가 생성될 때 한 번만 실행되는 초기화 구문이다.- 이것은 클로저가 처음 생성될 때만 실행되고, 이후 클로저의 함수 본문이 실행될 때마다
i
값이 변경된다.
package main
func foo() func() int {
i := 10 // f := foo() 할때만 실행된다
return func() int {
i++
return i
}
}
func main() {
f := foo()
n := f() + f()
println(n) // 23
f2 := foo()
n2 := f2()
println(n2) // 11
}
defer
- 파일 / 네트워크 자원 등의 임시 자원은 향후 정리될 필요가 있다. 이런 경우 defer을 사용한다.
- defer은 LIFO(후입선출)이다. 마지막 defer가 먼저 실행된다.
- defer 클로저 내의 클로저는 return 문이 실행된 후에 실행된다.
func example() {
defer func() int {
return 2
}()
}
func getFile(name string) (*os.File, func(), error){
file, err := os.Open(name)
if err != nil {
return nil, nil, err
}
return file, func() {
file.Close()
}, err
}
func main() {
f, closer, err := getFile("file.txt")
if err != nil {
log.Fatal(err)
}
defer closer()
// file working //
}
Share article