Go 1.22의 for 루프 변수 스코프 변경사항

문제 상황

사내 배치 서버를 Go 1.22로 업그레이드하면서 테스트 케이스 일부가 실패했다. for 루프 변수의 스코프 변경 때문이었다.

기존 Go 1.21 이하에서는 루프 변수가 반복마다 재할당되는 방식이었다.

var funcs []func()
for i := 0; i < 3; i++ {
    funcs = append(funcs, func() {
        fmt.Println(i) // Go 1.21: 모두 3 출력
    })
}

변경 내용

Go 1.22부터는 각 반복마다 새로운 변수가 생성된다. 클로저가 의도한 대로 동작하게 되었다.

// Go 1.22
for i := 0; i < 3; i++ {
    funcs = append(funcs, func() {
        fmt.Println(i) // 0, 1, 2 출력
    })
}

마이그레이션 이슈

문제는 기존 코드에서 이 버그를 "알고" 우회했던 부분들이었다.

// 기존 우회 코드
for i := 0; i < len(items); i++ {
    i := i // 명시적 복사
    go func() {
        process(items[i])
    }()
}

1.22에서는 이중으로 변수가 생성되지만 동작은 정상이다. 다만 불필요한 코드가 되었다.

실제 영향

우리 코드베이스에서는 워커 풀 패턴에서 한 건의 실제 버그를 발견했다.

// 버그가 있던 코드
for _, job := range jobs {
    if job.Status == "pending" {
        continue
    }
    wg.Add(1)
    go worker(job) // 1.21에서는 마지막 job만 처리
}

1.22에서는 정상 동작하지만, 1.21 환경에서는 조용히 실패하고 있었다.

대응 방안

  1. go vet이 이제 이런 패턴을 감지한다
  2. 테스트 커버리지가 충분하다면 1.22 업그레이드 권장
  3. 기존 우회 코드는 점진적으로 정리

당장 급한 버그는 아니었지만, Go 팀이 10년 넘게 끌어온 이슈를 드디어 해결한 것이라 환영할 만한 변경이다.