1. 문제 정의
Go로 처음 코딩을 시작하면 흔히 부딪히는 컴파일 에러가 있습니다. 변수나 패키지를 선언했지만 아직 사용하지 않으면 빌드가 멈춥니다.
| |
사용자가 “나중에 쓰려고 선언해 둔 것뿐인데 왜 빌드를 막느냐"라고 느끼는 지점이 바로 이 에러입니다. 실제 StackOverflow 질문(21743841, 490점)도 같은 불만에서 시작합니다.
- 증상 fingerprint
- 에러 메시지:
XXX declared and not used,XXX imported and not used: "패키지" - 발생 단계:
go build/go run컴파일 시점 - 관련 도구: Go 컴파일러 (gc), Go 1.x 전체
- 흔한 오해: “에러를 끄는 플래그가 있을 것이다”, “임시로 선언해 두면 되는 것이 아닌가”
- 빠른 판단 기준: 에러에
declared and not used가 보이면 빈 식별자_문제,imported and not used가 보이면 임포트 문제
- 에러 메시지:
2. 최소 재현 코드
에러를 가장 짧게 재현하는 코드는 다음과 같습니다.
| |
| |
임포트된 fmt를 한 번도 쓰지 않고, 선언한 i를 한 번도 읽지 않았기 때문에 두 에러가 동시에 발생합니다.
3. 에러 발생 이유
이 에러는 버그가 아니라 Go 팀의 공식 설계 결정입니다. Go FAQ에는 다음과 같은 명시가 있습니다.
미사용 변수의 존재는 버그를 암시할 수 있고, 미사용 임포트는 컴파일 속도를 늦춘다. 코드 트리에 미사용 임포트가 충분히 쌓이면 전체가 매우 느려질 수 있다. 이런 이유로 Go는 둘 다 허용하지 않는다.
즉 두 가지 목적이 있습니다.
| 목적 | 미사용 변수 | 미사용 임포트 |
|---|---|---|
| 코드 품질 | 버그 가능성 조기 발견 (선언만 하고 안 쓰는 로직은 의심) | 불필요한 의존성 제거 |
| 성능 | 미사용 코드로 인한 혼란 방지 | 컴파일/링크 속도 저하 방지 |
| 가독성 | “선언된 변수는 반드시 쓰인다"는 일관성 보장 | 남이 읽어도 의도가 명확 |
- 원인 후보 매트릭스 (root_cause_matrix)
| 원인 후보 | 확인 방법 | 해당 시 증상 | 해결 방향 |
|---|---|---|---|
| 변수 선언 후 미사용 | 에러의 파일·라인 확인 | i declared and not used | 실제 사용하거나 빈 식별자 _ = i |
| 임포트 후 미사용 | go vet / 에러 메시지 | imported and not used: "pkg" | 임포트 제거 또는 _ "pkg" |
| 시험 삼아 주석 처리한 코드 | 에러가 사라진 직후 발생 | 미사용 선언이 연쇄 발생 | 나중에 쓸 예정이면 _로 임시 우회 |
4. 수정 코드
방법 A — 빈 식별자 _ 사용 (임시 우회)
빈 식별자 _에 대입하면 “일부러 안 쓴다"는 의도를 컴파일러에 전달해 에러를 없앱니다.
| |
| |
_ = i는 변수를 읽은 것과 같은 효과를 내고, _ "fmt"는 임포트된 패키지를 “이니셜라이즈만 하고 사용은 보류"하게 만듭니다. 이 방식은 유효한 우회책이지만 임시방편이라는 점을 분명히 인지해야 합니다.
방법 B — 코드 정리 (권장)
“나중에 쓰려고” 선언한 변수는 대부분 실제로는 로직이 완성되면서 바로 사용되거나, 그대로 사라져야 합니다. 아래처럼 정리하면 에러가 없어질 뿐 아니라 코드가 더 깔끔해집니다.
| |
| |
- 해결책 비교
| 해결책 | 장점 | 단점 | 적합한 상황 |
|---|---|---|---|
빈 식별자 _ = i | 코드 수정 최소, 에러 즉시 해소 | 쓰지 않는 로직이 남아 혼란 유발 가능 | 개발 중간 임시 확인·실험 코드 |
빈 임포트 _ "pkg" | 부작용(init)만 실행하고 싶을 때 필요 | 의존성을 억지로 유지 | 패키지 init 등록 목적 |
| 실제 사용하도록 코드 작성 | 의도가 명확, 완성된 로직 | 수정량이 상대적으로 큼 | 본격 기능 구현 |
| 선언 자체 제거 | 가장 깔끔, 컴파일 속도 유지 | 해당 변수를 정말 안 쓸 때만 가능 | 사용할 계획이 없는 경우 |
- 실패한 해결책 (잘못된 해결책)
- “컴파일러 플래그로 에러를 끄기” — Go는 미사용 변수·임포트에 대한 경고를 끄는 공식 플래그를 제공하지 않습니다. 이 에러는 고의적 설계이므로 끄는 방법 자체가 없습니다.
- “선언만 남겨 두고 나중에 정리” — 위험합니다. 프로덕션에 들어가기 전
go vet과 CI 빌드가 항상 이 에러로 실패하게 되어 배포가 막힙니다. 미사용 선언은 반드시 그 자리에서 처리해야 합니다.
5. 검증 방법
수정 후 에러가 사라졌는지, 그리고 코드가 실제로 동작하는지 확인합니다.
| |
| |
- 검증 명령 (verification_command)
go build ./...— 전체 패키지 컴파일 에러 확인go vet ./...— 미사용·비정상 코드 정적 분석go run .— 실제 실행해서 로직 동작 확인
6. 실전 적용 주의사항
빈 식별자
_는 영구 해결책이 아닙니다. 특히_ = value를 반복해서 쓰다 보면 “뭔가 쓰고 있는 것처럼 보이지만 아무것도 하지 않는” 죽은 코드가 쌓입니다. 실험 후에는 반드시 실제 로직을 완성하거나 선언을 지우세요._ "pkg"는 패키지의init()부작용만 필요할 때 용법이 다릅니다. 예를 들어_ "net/http/pprof"처럼 임포트만으로 등록 효과를 내는 패턴은 정당한 사용입니다. 하지만 단순히 “나중에 쓸 예정"으로 쓰는 것은 피해야 합니다.검증 환경 및 버전별 차이: 이 동작은 Go 1.x 전체에서 일관됩니다. Go 1.0부터 현재 버전까지 미사용 변수·임포트는 계속 컴파일 에러로 처리되며, 이 점은 문서화된 공식 입장입니다. 따라서 버전을 올려도 “에러가 사라지는” 변화는 없습니다 — 오히려
go vet등 정적 분석이 강화되는 방향으로 발전했습니다.운영 예방책 (재발 방지): 로컬 뿐 아니라 CI 파이프라인에
go build ./... && go vet ./...를 포함해 미사용 선언이 머지되는 순간 바로 잡아내도록 하세요. 그래야 개발 속도를 늦추는 “선언만 해두고 나중에 정리"가 운영 코드로 새어들어 가지 않습니다.DevTrace verdict (핵심 판단): 이 문제의 핵심은 “왜 에러가 나는가"를 이해하는 데 있습니다 — Go는 미사용 변수를 버그 신호로, 미사용 임포트를 컴파일 속도 저하 요인으로 보고 둘 다 의도적으로 금지했으며, 빈 식별자
_는 임시 우회 수단일 뿐 올바른 장기 해결책은 코드 정리입니다.
출처
- StackOverflow: How to avoid annoying error “declared and not used”
- Go FAQ의 미사용 변수·임포트 관련 공식 입장 (질문 댓글 인용, 위 출처 내)