Go 언어 클로저에 대한 콩 지식
배경
for분에 함수를 쓸 때, 특히 for분의 범위와 함수의 조합에 의해, 클로저가 생성되어 함수의 실행 타이밍이 for분과 일치하지 않는 경우는, 버그가 발생하기 쉽습니다.
예를 들어, 자바스크립트에는 다음과 같은 클로저 전형적인 예가 있습니다.
자바 스크립트 콩 지식 (let, var, 클로저에 대한 인터뷰 문제)
Javascript에서는 let이라는 변수 선언 방법을 활용하여 잘 for분 함께 있는 클로저 문제점을 해소할 수 있습니다만, Go 언어라면, 어떻게 해소할 수 있습니까?
문제
코드
func main() {
n := 5
funcs := []func(){}
for i:=0;i<n;i++ {
// fmt.Println(&i) // コメントアウトを外してみたら、iのメモリアドレスは同じものです。
funcs = append(funcs, func() {
fmt.Print(i)
})
}
for i:=0;i<n;i++ {
funcs[i]()
}
}
출력
5
5
5
5
5
원인
두 가지 원인이 있습니다.
자바 스크립트라면 for 분에 i를 let로 정의하여 문제를 해결할 수 있지만 Go 언어는 어떻게됩니까?
여러가지 조사했습니다.
해결 방법 1
새로운 변수 i를 만들어, 새로운 i를 메모리장에서 개척해, funcs 슬라이스에 넣는 함수는 이쪽의 i를 기억합니다.
코드
func main() {
n := 5
funcs := []func(){}
for i:=0;i<n;i++ {
i := i
// fmt.Println(&i) //コメントアウトを外して見たら、iのメモリアドレスはそれぞれ異なります。
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for i:=0;i<n;i++ {
funcs[i]()
}
}
출력
0
1
2
3
4
해결 방법 2
실행된 함수 A가 함수 B를 반환하고, 함수 B를 funcs 슬라이스에 넣습니다. 함수 A에 전달한 인수는 값 전달이므로 함수 A가 실행될 때 i가 새로 만들어집니다.
그러면 함수 B는 함수 A와 클로저를 생성하고, 함수 A 안에 새로운 i가 메모리 필드에서 개척되고, 함수 B가 그 i를 참조합니다. 각 함수 B는 각각의 i를 참조합니다.
코드
func main() {
n := 5
funcs := []func(){}
for i:=0;i<n;i++ {
funcs = append(funcs, func(i int) func() {
// fmt.Println(&i) // コメントアウトを外してみたら、iのメモリアドレスはそれぞれ異なります。
return func() {
fmt.Println(i)
}
}(i))
} // ここ → 関数Aにforループのiを渡し、関数Bを返されます。
for i:=0;i<n;i++ {
funcs[i]()
}
}
출력
0
1
2
3
4
덧붙여서, 함수 A에 인수를 포인터 전달로 실행하면 어떻게됩니까?
for i:=0;i<n;i++ {
funcs = append(funcs, func(i *int) func() {
fmt.Println(i)
return func() {
fmt.Println(*i)
}
}(&i))
}
당연히 모든 i는 동일한 메모리 주소를 참조하고 모든 func의 출력은 동일한 5입니다.
0xc00001c080
0xc00001c080
0xc00001c080
0xc00001c080
0xc00001c080
5
5
5
5
5
참고 자료
Reference
이 문제에 관하여(Go 언어 클로저에 대한 콩 지식), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/xu1718191411/items/70550780d928dec96cab텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)