
Go 반복문, 왜 이것만 제대로 알아도 절반은 성공일까요?
새로운 언어를 배울 때 가장 당혹스러운 순간 중 하나는 내가 알던 상식이 통하지 않을 때예요. 파이썬의 for나 자바의 while에 익숙한 상태에서 Go 언어를 처음 접하면, “왜 while 문이 없지?”라는 의문이 가장 먼저 들 거예요. Go는 설계 철학 자체가 극도의 단순함을 지향하기 때문에, 모든 반복 로직을 단 하나의 키워드인 for로 처리하도록 만들었어요.
이게 왜 중요하냐고요? 단순해 보이지만, 이 단순함 속에 Go만의 독특한 효율성과 주의점이 숨어 있기 때문이에요. 반복문의 조건식을 잘못 설정해서 프로그램이 무한 루프에 빠지거나, 슬라이스의 범위를 벗어나 런타임 에러(panic)를 마주하며 밤을 지새우는 주니어 개발자들을 정말 많이 봤어요. Go의 for 문은 단순하지만, 그 활용법은 무궁무진해요.
오늘 이 글을 끝까지 읽고 나면, 더 이상 반복문을 작성할 때 주저하지 않게 될 거예요. 단순히 문법을 외우는 것을 넘어, 상황에 따라 어떤 반복문을 써야 성능과 가독성 면에서 유리한지 판단하는 눈을 갖게 될 거예요. 복잡한 중첩 루프를 깔끔하게 탈출하는 방법부터, Go 언어의 정수를 담은 range 활용법까지 실전 위주로 정리해 드릴게요.
- Go 언어의 유일한 반복문,
for의 3가지 변형 형태 - 슬라이스, 맵, 문자열을 완벽하게 다루는
range활용법 - 무한 루프와 중첩 루프를 제어하는
break,continue테크닉 - 입문자가 가장 자주 범하는 5가지 치명적인 실수와 해결책
반복문을 쓰기 전, 이것만큼은 꼭 체크하세요
본격적으로 코드를 치기 전에 우리가 먼저 정립해야 할 개념이 있어요. Go의 반복문은 단순히 숫자를 세는 도구가 아니에요. 데이터 구조인 슬라이스(Slice), 배열(Array), 맵(Map), 채널(Channel)을 어떻게 순회하느냐에 따라 코드의 성능이 완전히 달라질 수 있어요.
특히 변수 범위(Scope)를 조심해야 해요. Go의 for 문 안에서 선언된 변수가 루프 밖에서도 영향을 미치는지, 혹은 매 루프마다 새롭게 생성되는지는 매우 중요한 이슈예요. 이를 잘못 이해하면 클로저(Closure)를 사용할 때 예상치 못한 버그를 만나게 된답니다.
상황에 맞는 반복문 선택을 돕기 위해 아래 비교 표를 준비했어요. 어떤 상황에 어떤 문법을 가져다 써야 할지 기준을 세워보세요.
| 반복 방식 | 주요 용도 | 장점 | 주의점 |
|---|---|---|---|
| 표준형 (C-style) | 정해진 횟수만큼 반복 | 인덱스 제어가 매우 정밀함 | 조건식 오류 시 무한 루프 위험 |
| Range형 | 컬렉션 전체 순회 | 가독성이 높고 안전함 | 인덱스와 값을 동시에 다룸 |
| 조건형 (While-like) | 특정 조건이 만족될 때까지 | 유연한 종료 조건 설정 | 상태 업데이트 누락 주의 |
| 무한 루프 | 서버 대기, 이벤트 루프 | 지속적인 작업 수행 가능 | 반드시 탈출 조건(break) 필요 |
준비가 되셨나요? 이제 실제 코드가 어떻게 움직이는지 단계별로 깊게 파고들어 볼게요. 이 가이드를 따라가기만 해도 Go 반복문의 고수가 될 수 있어요.
Go 반복문 마스터를 위한 단계별 실전 가이드
Go의 반복문은 크게 세 가지 모습으로 나타나요. 각 단계별로 실제 프로덕션 환경에서 어떻게 쓰이는지 자세히 살펴볼게요.
STEP 1. 가장 기본이 되는 표준형 for 루프
우리가 흔히 아는 C 언어 스타일의 반복문이에요. 세 가지 요소인 초기화 문장, 조건식, 증감식으로 구성돼요. 특정 횟수만큼 정확히 반복해야 하거나, 인덱스를 조절하며 건너뛰어야 할 때 사용해요.
예를 들어, 슬라이스의 요소를 하나씩 확인하면서 인덱스를 2씩 증가시키며 확인해야 한다면 이 방식이 가장 적합해요. 하지만 조건식을 잘못 적으면 프로그램이 멈추지 않는 무서운 상황이 생길 수 있으니 항상 주의해야 해요.
for i := 0; i < 10; i++ { ... }1.
i := 0: 시작할 때 딱 한 번 실행돼요.2.
i < 10: 루프를 돌 때마다 이 조건이 참인지 확인해요.3.
i++: 한 번의 루프가 끝날 때마다 실행돼요.STEP 2. 컬렉션을 위한 마법, for range 활용하기
실무에서는 표준형보다 이 range를 훨씬 더 많이 사용해요. 슬라이스, 배열, 맵, 문자열 등을 순회할 때 인덱스와 값을 아주 간편하게 가져올 수 있거든요. Go 개발자답게 코드를 짜고 싶다면 range와 친해져야 해요.
슬라이스를 순회할 때는 인덱스와 값을 모두 받을 수 있고, 만약 인덱스가 필요 없다면 언더스코어(_)를 사용해 무시할 수 있어요. 맵(Map)을 순회할 때는 키(Key)와 값(Value)을 가져오게 되는데, 여기서 한 가지 팁을 드리자면 맵의 순회 순서는 매번 달라질 수 있다는 점을 꼭 기억해야 해요. 예측 가능한 순서가 필요하다면 키를 먼저 슬라이스로 만든 뒤 정렬해서 순회하는 전략을 써야 해요.
문자열 순회 시에도 매우 유용해요. Go의 문자열은 UTF-8로 인코딩되어 있는데, range를 사용하면 바이트 단위가 아니라 룬(Rune, 유니코드 코드 포인트) 단위로 안전하게 한 글자씩 읽어올 수 있어요. 한글처럼 여러 바이트를 차지하는 문자를 다룰 때 range를 쓰지 않으면 글자가 깨지는 참사가 발생할 수 있답니다.
STEP 3. Go 버전의 while 문, 조건식 반복문
Go에는 명시적인 while 키워드가 없어요. 대신 for 문에 조건식만 딱 하나 남겨두면 그게 바로 while 문이 돼요. 특정 상태가 변할 때까지 계속해서 무언가를 수행해야 하는 로직에서 아주 유용해요.
예를 들어, 네트워크 연결이 끊기지 않을 때까지 계속 데이터를 읽어오거나, 큐(Queue)에 데이터가 남아있는 동안 계속 처리하는 로직을 짤 때 사용해요. 이때 가장 중요한 건 조건을 거짓으로 만드는 변화가 루프 내부에서 반드시 일어나야 한다는 점이에요. 그렇지 않으면 CPU 점유율이 치솟는 무한 루프의 늪에 빠지게 돼요.
STEP 4. 흐름을 제어하는 break와 continue
반복문 도중에 흐름을 바꾸고 싶을 때가 있죠? 그럴 땐 break와 continue를 사용해요. continue는 현재 루프의 남은 코드를 건너뛰고 바로 다음 반복으로 넘어가는 것이고, break는 반복문을 아예 즉시 종료하고 탈출하는 거예요.
특히 중첩 반복문(Nested Loop)을 쓸 때, 안쪽 루프에서 탈출했는데 바깥쪽 루프는 여전히 돌고 있어서 당황한 적이 있을 거예요. 이럴 때는 라벨(Label)을 사용하면 돼요. 루프 앞에 이름을 붙여주고 break 라벨이름이라고 쓰면, 중첩된 모든 루프를 한 번에 깨끗하게 탈출할 수 있어요. 이건 코드를 훨씬 깔끔하게 만들어주는 아주 고급 기술이에요.
STEP 5. 실전 시나리오: 슬라이스 필터링하기
이 모든 것을 종합해서, 실무에서 자주 쓰는 '특정 조건의 데이터만 추출하는 로직'을 예시로 들어볼게요. 1부터 20까지의 숫자 중 짝수만 골라내어 새로운 슬라이스에 담는 과정이에요.
먼저 결과값을 담을 빈 슬라이스를 준비해요. 그 다음 for range를 사용하여 전체 숫자를 순회하면서, if 문으로 짝수인지 확인하죠. 조건에 맞으면 append 함수로 결과 리스트에 추가해요. 이 과정은 데이터 처리 파이프라인의 가장 기초적인 형태랍니다. 단순해 보이지만, 이 구조가 확장되어 수만 개의 데이터를 처리하는 엔진이 되는 거예요.
자주 하는 실수와 해결법
실전에서 개발자들이 가장 많이 겪는 당혹스러운 상황들을 정리했어요. 코드를 작성한 후 스스로 검토할 때 이 리스트를 활용해 보세요.
- ❌ 인덱스 범위 초과(Out of Range)
왜 발생하는가: 슬라이스의 길이를 잘못 계산하거나, 인덱스를 수동으로 조절하다가 마지막 요소를 넘어섰을 때 발생해요.
✅ 해결법: 가급적range를 사용하여 인덱스를 직접 다루지 마세요. 꼭 필요하다면len(slice)를 항상 확인하세요. - ❌ 무한 루프 발생
왜 발생하는가: 조건식이 항상 참이거나, 반복문 내부에서 탈출 조건(break)이 충족되지 않을 때 발생해요.
✅ 해결법: 조건식의 변수가 루프 내부에서 반드시 변경되는지, 혹은 종료 조건이 명확한지 다시 검토하세요. - ❌ 클로저에서의 루프 변수 캡처 문제
왜 발생하는가: 루프 변수의 주소값을 고루틴(Goroutine)이나 클로저에 넘길 때, 모든 고루틴이 마지막 루프 값만 참조하는 문제가 생겨요.
✅ 해결법: 루프 내부에서 변수를 새로 선언(v := v)하여 각 반복마다 독립적인 복사본을 만들어 사용하세요. - ❌ 맵 순회 순서의 불일치
왜 발생하는가: Go의 맵은 순서가 보장되지 않도록 설계되었어요. 루프를 돌 때마다 결과가 달라질 수 있어요.
✅ 해결법: 순서가 중요하다면 키(Key)를 따로 추출해 정렬한 뒤, 그 순서대로 맵에 접근하세요. - ❌ 문자열 바이트/룬 혼동
왜 발생하는가: 한글 같은 멀티바이트 문자를 인덱스로 접근하면 글자가 깨져요.
✅ 해결법: 문자를 하나씩 처리할 때는 반드시for range를 사용해 룬 단위로 순회하세요.
자주 묻는 질문
Q. Go에서 while 문은 어떻게 사용하나요?
A. Go에는 별도의 while 문이 없어요. 대신 for 조건식 { ... } 형태로 쓰면 동일하게 작동해요. 조건이 참인 동안 계속 실행되는 구조예요.
Q. for range에서 인덱스 없이 값만 가져오려면 어떻게 하나요?
A. 인덱스 자리에 언더스코어(_)를 넣어주면 돼요. for _, value := range slice { ... }와 같이 작성하면 인덱스는 무시하고 값만 깔끔하게 쓸 수 있어요.
Q. 중첩 반복문에서 바깥쪽 반복문을 한 번에 탈출하고 싶을 땐 어떻게 하죠?
A. 라벨을 사용하세요. 루프 앞에 OuterLoop: 처럼 이름을 붙이고, 안쪽에서 break OuterLoop라고 명령하면 바깥쪽까지 한 번에 탈출해요.
Q. map을 순회할 때 왜 매번 순서가 바뀌나요?
A. Go 설계자들이 맵 순회 순서에 의존하는 코드를 짜지 못하도록 의도적으로 무작위성을 넣었기 때문이에요. 결과의 일관성이 필요하다면 키를 정렬한 뒤 접근해야 해요.
Q. 문자열을 반복문으로 돌릴 때 한글이 깨지면 어떡하죠?
A. 인덱스로 바이트 단위 접근을 하고 계실 확률이 높아요. range를 사용하면 Go가 알아서 유니코드(Rune) 단위로 나누어 주기 때문에 안전하게 한글을 읽을 수 있어요.
반복문 정복을 위한 최종 요약
지금까지 Go 언어의 유일한 반복문인 for에 대해 깊이 있게 알아보았어요. 반복문은 단순해 보이지만, 어떻게 쓰느냐에 따라 코드의 품질과 프로그램의 안정성이 결정되는 매우 중요한 도구예요.
- Go의 모든 반복은
for키워드 하나로 이루어져요. - 정밀한 제어가 필요하면 표준형, 컬렉션 순회는 range형을 쓰세요.
while문이 필요할 땐 조건식만 있는 for를 사용하세요.- 슬라이스나 문자열 순회 시 인덱스 오류와 유니코드 문제를 항상 조심하세요.
- 중첩 루프 탈출은 라벨(Label)을 활용하면 매우 깔끔해요.
- 맵(Map) 순회 시에는 결과 순서가 매번 바뀔 수 있음을 명심하세요.
이제 여러분은 Go의 반복문을 다룰 준비가 끝났어요. 이론을 배웠으니 이제 직접 코드를 작성해 볼 차례예요. 오늘 배운 내용을 바탕으로 작은 연습 프로그램을 만들어 보는 건 어떨까요?
오늘 할 일: 슬라이스에 담긴 숫자들 중 특정 조건의 값만 필터링하는 코드 직접 짜보기
이번 주 할 일: range와 label을 활용한 중첩 루프 예제 3개 이상 만들어보기
실행 직전 할 일: 작성한 코드에 무한 루프 위험이 없는지 다시 한번 눈으로 검토하기
혹시 코드를 짜다가 도저히 해결되지 않는 부분이 있나요? 아니면 Go의 반복문에 대해 더 깊게 알고 싶은 궁금한 점이 있으신가요? 궁금한 점은 댓글로 남겨 주시면 친절히 답변해 드릴게요. 우리 함께 성장해 나가요!
관련해서 더 깊은 Go 언어의 원리가 궁금하다면 Go 반복문 완전 정복 가이드 글도 함께 읽어 보시기를 추천해요.