Go 1.22에서 추가된 for 루프 변수 스코프 변경 적용기

문제 상황

회사 프로젝트를 Go 1.22로 업그레이드하면서 for 루프 변수 스코프 변경 사항을 적용했다. 기존에는 루프 변수가 반복마다 재사용되어 고루틴에서 예상치 못한 동작이 발생했었다.

// Go 1.21 이하에서 문제가 되던 코드
for _, user := range users {
    go func() {
        // 모든 고루틴이 마지막 user를 참조
        processUser(user)
    }()
}

기존에는 클로저로 명시적으로 캡처해야 했다.

// 기존 해결 방법
for _, user := range users {
    user := user // 명시적 복사
    go func() {
        processUser(user)
    }()
}

Go 1.22의 변경 사항

Go 1.22부터는 for 루프 변수가 반복마다 새로 생성된다. 별도의 복사 없이도 의도한 대로 동작한다.

// Go 1.22+에서는 이대로 정상 동작
for _, user := range users {
    go func() {
        processUser(user) // 각 고루틴이 올바른 user 참조
    }()
}

마이그레이션 과정

  1. go.mod에서 go 1.22로 버전 명시
  2. go vet으로 불필요해진 변수 복사 패턴 탐색
  3. 테스트 케이스 실행으로 동작 검증

실제로 워커 풀 패턴을 사용하던 배치 처리 코드에서 30줄 가량의 보일러플레이트를 제거할 수 있었다.

주의사항

기존 user := user 패턴은 Go 1.22에서도 여전히 유효하다. 하위 호환성 때문에 즉시 제거할 필요는 없지만, 새로운 코드에서는 생략해도 된다.

Go 1.21 이하와 호환성을 유지해야 하는 라이브러리라면 기존 패턴을 유지하는 것이 안전하다.