Learning Go - Chapter 5. 함수

choko's avatar
Jun 29, 2024
Learning Go - Chapter 5. 함수
 
 
 
 

함수는 값이다.

  • 함수를 값으로 사용하여 함수를 맵의 값으로 사용해 계산기를 만드는 예제
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) }
       
 

클로저

  • 함수 내부에 선언된 함수로, 클로저는 외부 함수에서 선언한 변수를 접근하고 수정할 수 있는것을 의미한다.
  • 함수는 값이고, 파라미터와 반환값을 사용하여 함수의 타입을 지정할 수 있기 때문에, 파라미터로 함수를 다른 함수로 넘길 수 있다.
  1. 파라미터로 함수를 전달
    1. 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 Slice(x any, less func(i, j int) bool)
        • 클로저 함수에서 people 변수를 사용하여 Age 오름차순으로 정렬
        •  
  1. 함수에서 함수 반환
    1. 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

Tom의 TIL 정리방