>백엔드 개발 >Golang >Go 언어의 for 루프는 얼마나 불쌍합니까?

Go 언어의 for 루프는 얼마나 불쌍합니까?

藏色散人
藏色散人앞으로
2022-11-07 16:48:132614검색

이 글은 golang tutorial 칼럼에서 Go for 루프에 대한 인터뷰 질문을 소개하기 위해 작성되었습니다. for 루프에 대해 얼마나 알고 계시는지 모르겠습니다. 아래에서는 for 관련 문제에 대해 자세히 설명하겠습니다. 필요한 친구들에게 도움이 되길 바랍니다!

for 루프와 관련된 Go 인터뷰 질문과 유출이 얼마나 많은지 모르겠습니다. 오늘 저는 주말 동안 자세히 살펴보고 루프 변수 의미 체계를 재정의하는 방법을 발견했습니다.

유명한 하드코어 보스인 Russ Cox는 자신이 이 문제를 연구해 왔으며 10년의 경험을 통해 현재 의미론의 비용이 매우 높다는 것을 보여준다고 말했습니다.

문제

  • 사례 1: 주소 문자 가져오기

Go 언어에서는 for 문을 작성할 때 연산 결과와 추측 결과가 일치하지 않는 경우가 있습니다. 예를 들어 아래 첫 번째 사례의 코드는 다음과 같습니다.

var all []*Itemfor _, item := range items {
	all = append(all, &item)
}

이 코드에 문제가 있나요? all 변수의 item 변수에는 무엇이 저장되나요? 각 루프의 아이템 값인가요?

실제로 for 루프 중에 매번 동일한 항목이 변수에 저장되는데, 이것이 마지막 루프의 항목 값입니다.

Go 인터뷰에 자주 등장하는 질문인데, 고루틴과 결합하면 더 흥미롭습니다. 결국 출력이 제대로 되지 않는 등의 문제가 있습니다.

이 문제를 해결하려면 다음과 같이 프로그램을 다시 작성해야 합니다.

var all []*Itemfor _, item := range items {
	item := item
	all = append(all, &item)
}

항목 변수를 다시 선언하고 for 루프의 항목 변수를 저장한 다음 추가합니다.

  • 사례 2: 폐쇄 함수

다음은 두 번째 사례의 코드입니다.

var prints []func()for _, v := range []int{1, 2, 3} {
	prints = append(prints, func() { fmt.Println(v) })
}for _, print := range prints {	print()
}

이 프로그램의 출력은 무엇입니까? &가 없으면 주소 문자를 얻으려면 1, 2, 3이 출력됩니까?

출력 결과는 3, 3, 3입니다. 왜 이런가요?

문제의 핵심 중 하나는 클로저 기능입니다. 실제로 모든 클로저는 동일한 v를 인쇄합니다. for 루프가 끝난 후 v의 최종 값이 3으로 설정되기 때문에 출력은 3입니다.

원하는 효과를 얻으려면 여전히 범용 재할당을 사용해야 합니다. 다시 작성한 코드는 다음과 같습니다.

for _, v := range []int{1, 2, 3} {
		v := v
		prints = append(prints, func() { fmt.Println(v) })
	}

v := v 문을 추가하면 프로그램 출력 결과는 1, 2, 3입니다. 당신이 작성한 Go 프로젝트를 주의 깊게 살펴보십시오. 모두 익숙합니까? 이 변환 방법으로 우리가 승리했습니다.

특히 고루틴 글쓰기 방식을 사용하면 많은 학생들이 여기서 뒤집을 가능성이 높아집니다.

Solution

  • Repair ideas

실제로 Go 코어 팀은 for 루프의 구문을 재정의하기 위해 내부 및 커뮤니티에서 오랫동안 논의해 왔습니다. 달성하려는 목표는 다음과 같습니다. 루프를 실행할 때마다가 아니라 반복할 때마다 루프 변수를 만듭니다 .

해결책은 각 반복 변수 x의 각 루프 본문 시작 부분에 암시적 재할당 , 즉 을 추가하는 것입니다. 이는 위 프로그램에 암시된 함정을 해결할 수 있습니다. Go 팀이 하는 일은 컴파일러에서 암시적으로 처리하는 것 외에는 지금 하는 일과 동일합니다. x := x

  • 사용자가 스스로 결정하도록 하세요

더 당황스러운 점은 Go 팀이 Proposal: Go 2 전환에서 언어 재정의를 금지하므로 rsc가 이를 직접 수행할 수 없다는 것입니다.

따라서 각 패키지의 go.mod 파일에 있는 go 줄을 기반으로 의미를 변경하여 이러한 "깨짐"을 제어하는 ​​것은 사용자의 몫입니다.

이 글에서 논의한 for 루프를 Go1.30의 반복으로 변경하면 go.mod 파일의 go 버전 선언이 핵심이 됩니다.

아래와 같이:

Go 1.30 이상에서는 매번 변수를 반복하지만 이전 Go 버전에서는 매번 변수를 반복합니다.

이렇게 하면 위에서 언급한 for 루프 문제가 어느 정도 해결될 것입니다.

요약

for 루프의 변수 문제는 주요 Go 심사위원들이 항상 즐겨 찾는 주제였습니다. 또한 실제로 Go 코드를 프로그래밍할 때 이러한 함정에 직면하게 되는 것도 사실입니다.

rsc는 go.mod 파일을 개척하고 go 버전 선언을 사용하여 의미를 수정하기를 희망하지만(추가 및 삭제는 허용되지 않습니다) 이는 의심할 여지 없이 Go1 호환성 보장에 대한 백도어를 열어줍니다.

이 변경 사항이 구현되면 이전 버전과 이후 버전의 Go 간에 의미 체계가 달라집니다. go.mod 파일의 의미 스위치가 될 수도 있습니다.

이것은 분명히 생각하기 매우 어려운 질문입니다.

위 내용은 Go 언어의 for 루프는 얼마나 불쌍합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제