Go 언어에서 익명 함수(함수 리터럴, 클로저)는 함수형 스타일, 콜백, 알고리즘의 간결한 캡슐화를 지원하기 위해 등장했습니다. 이들은 컬렉션 처리, 비동기 작업 및 매개변수 전달에 자주 사용됩니다.
익명 함수가 없다면 코드가 과도해집니다: 각 처리를 별도의 이름이 있는 함수로 가져가야 합니다. 그러나 이들로 인해 변수 "캡처" 작동 방식, 메모리 저장 위치, 인수로 전달할 때의 특성 등 여러 질문이 발생합니다. 변수를 외부에서 수정할 경우 캡처가 보호됩니까? 자주 발생하는 오류는 루프 내 변수 캡처를 잘못 진행하는 것입니다.
익명 함수는 리터럴로 선언되고 변수에 할당되거나 즉시 사용될 수 있습니다. 익명 함수가 외부 영역의 변수에 접근하면 이 변수는 "캡처"되어 클로저의 생명 주기 동안 유지됩니다. 함수의 매개변수로 익명 함수를 전달할 때는 일반적으로 시그니처와 호환되는 func 유형으로 전달됩니다. 대부분의 문제는 루프의 변수를 캡처할 때 발생하므로, 클로저로 로직을 감싸고자 한다면 반드시 루프 내에서 새로운 변수를 생성해야 합니다.
코드 예시:
func operate(nums []int, op func(int) int) []int { res := make([]int, len(nums)) for i, n := range nums { res[i] = op(n) } return res } func main() { arr := []int{1, 2, 3} out := operate(arr, func(x int) int {return x * x}) fmt.Println(out) // [1 4 9] }
주요 특징:
익명 함수를 통해 변수가 변경 가능한 값으로 캡처될 때 무엇이 발생합니까?
모든 클로저는 동일한 변수를 캡처하며, 루프를 빠져나간 후 함수를 호출할 때 동일한 값을 얻게 됩니다.
코드 예시:
func main() { a := []func(){} for i := 0; i < 3; i++ { a = append(a, func() { fmt.Println(i) }) } for _, f := range a { f() } // 3 3 3 }
이를 피하려면 루프 본문에 새로운 변수를 생성하십시오:
for i := 0; i < 3; i++ { j := i a = append(a, func() { fmt.Println(j) }) // 0 1 2 }
익명 함수를 interface{} 타입의 값으로 사용할 수 있습니까?
함수는 interface{}와만 호환되며 다른 인터페이스와는 호환되지 않으며 서로 비교할 수 없습니다(니lt 제외). 클로저를 interface{}로 전달하면, func 시그니처로 형변환하여만 호출할 수 있습니다.
익명 함수가 재귀적일 수 있습니까?
네, 그러나 클로저에 대한 이름 변수를 먼저 선언한 후 그 함수 자신에게 할당해야 합니다.
코드 예시:
var fib func(n int) int fib = func(n int) int { if n < 2 { return n } return fib(n-1) + fib(n-2) } fmt.Println(fib(10)) // 55
콜백 목록을 순회하면서 개발자가 변수 반복자 캡처로서 핸들러를 클로저로 바인딩합니다. 모든 콜백이 일치하지 않는 값으로 작업하여 버그를 발생시킵니다.
장점:
단점:
루프 내에서 각 클로저를 위한 새로운 변수를 생성하여 값의 정확한 캡처와 기대한 동작을 보장합니다.
장점:
단점: