함수 리터럴은 일종의 익명함수이다(즉 이름이 없다). 다른 말로는 람다함수라고 불리기도 한다(go언어에서). Go언어에서 함수 리터럴을 선언하는 방식은 아래와 같다
변수 := func(매개변수) 반환값 {}
예시는 아래와 같다.
func main() {
sum := func(a, b int) int {
return a + b
}
fmt.Println(sum(1, 2))
}
//결과
3
함수 리터럴은 JavaScript처럼 즉시실행 함수로 활용할 수 도 있다.
func main() {
func(a, b int) {
fmt.Println(a + b)
}(1, 2)
}
함수 리터럴은 상위 스코프의 변수도 활용할 수 있다.다만 주의할 점이 있다. 함수 리터럴 외부 변수를 함수 리터럴 내부로 가져오는것을 캡쳐
라고 한다. 캡쳐
는 값을 복사하는것이 아닌, 참조를 하는 형태이다. 값을 복사 방식으로 가져오는 JavaScript와의 차이점이다.
function test() {
const arr1 = new Array()
for (let i = 0; i < 5; i++) {
arr1.push(() => {
console.log("Print : ", i)
})
}
arr1.map((x) => x())
}
test()
// 결과
Print : 0
Print : 1
Print : 2
Print : 3
Print : 4
동일한 코드를 go언어로 바꾸면 아래와 같은 결과가 나오게 된다.
func main() {
functions := make([]func(), 5)
for i := 0; i < 5; i++ {
functions[i] = func() {
fmt.Println("Print : ", i)
}
}
for _, v := range functions {
v()
}
}
//결과
Print : 5
Print : 5
Print : 5
Print : 5
Print : 5
이를 방지하기 위해서는 각각의 i값을 변수에 복사한 후 각각의 함수 리터럴에서 복사한 변수를 캡쳐하도록 변경해주어야한다.
func main() {
functions := make([]func(), 5)
for i := 0; i < 5; i++ {
t := i // i값을 복사
functions[i] = func() {
fmt.Println("Print : ", t) // 순회시 캡쳐된 i값이 복사된 t변수를 캡쳐
}
}
for _, v := range functions {
v()
}
}
//결과
Print : 0
Print : 1
Print : 2
Print : 3
Print : 4