
반복문 for 치트시트: 왜 지금 배워야 할까요?
새벽 2시, 운영 중인 서버의 CPU 점유율이 갑자기 100%를 찍고 있어요. 당황해서 로그를 살펴보니 범인은 아주 단순한 코드 한 줄이었죠. 바로 조건식을 잘못 설정해서 멈추지 않고 계속 돌아가는 무한 루프였어요. Go 언어를 처음 접하는 분들이라면 누구나 한 번쯤 겪을 수 있는 아찔한 순간이에요.
Go 언어는 다른 언어들과 달리 while이나 do-while 같은 별도의 키워드가 없어요. 오직 for 문 하나로 모든 반복 작업을 처리해야 하죠. 이 점이 처음에는 단순해서 좋지만, 익숙하지 않으면 코드가 복잡해지거나 예상치 못한 오류를 만들기 쉬워요.
단순히 문법을 암기하는 것만으로는 부족해요. 실무에서 슬라이스를 효율적으로 순회하고, 맵(Map)의 데이터를 안전하게 꺼내 쓰며, 성능 저하 없이 반복문을 작성하는 감각이 필요해요. 오늘 정리해 드리는 Go 반복문 치트시트를 옆에 두고 실습한다면, 더 이상 반복문 때문에 밤을 지새울 일은 없을 거예요.
이 글에서는 다음과 같은 내용을 구체적으로 다뤄요.
- Go 반복문의 3가지 기본 형태와 작동 원리
- slice와 map을 가장 효율적으로 다루는 range 활용법
- 실무에서 바로 쓰는 핵심 코드 패턴과 주의사항
- 초보 개발자가 가장 많이 저지르는 실수 5가지와 해결책
반복문 작성 전 꼭 알아야 할 기본 개념
Go 언어의 철학은 단순함이에요. 반복문 역시 이 철학을 그대로 따라가죠. 복잡한 제어 구조를 여러 개 만드는 대신, 가장 강력한 도구 하나를 제대로 쓰는 데 집중해요. 본격적인 코딩에 들어가기 전에 우리가 어떤 기준으로 문법을 선택해야 할지 먼저 정리해 볼게요.
반복문의 종류와 선택 기준
Go에는 오직 for만 존재하지만, 어떻게 구성하느냐에 따라 그 역할이 완전히 달라져요. 상황에 맞는 적절한 형태를 선택하는 것이 코드의 가독성을 결정해요.
| 반복 형태 | 사용 시점 | 주요 특징 |
|---|---|---|
| 표준형 for | 인덱스를 직접 제어할 때 | 초기값, 조건식, 증감식을 명시해요. |
| 조건식 전용 for | 특정 조건이 충족될 때까지 반복 | 다른 언어의 while 문과 같아요. |
| 무한 루프 for | 내부에서 break로 탈출할 때 | 조건 없이 계속 실행돼요. |
| range 활용 for | 컬렉션(Slice, Map)을 순회할 때 | 인덱스와 값을 동시에 가져와요. |
반복문 학습을 위한 체크리스트
반복문을 제대로 이해하기 위해서는 단순히 문법을 아는 것을 넘어, 데이터가 메모리에 어떻게 담겨 있는지를 함께 고민해야 해요. 다음 요소들을 미리 머릿속에 그려보세요.
- 인덱스(Index)의 개념: 배열이나 슬라이스의 몇 번째 칸인지 정확히 인지하고 있나요?
- 조건식의 범위: 루프가 시작되는 시점과 끝나는 시점의 경계를 명확히 구분할 수 있나요?
- 변수의 생명주기: 루프 안에서 선언된 변수가 루프가 끝난 뒤에도 남아있는지 알고 있나요?
Go 1.22 버전부터는 반복문 변수의 생명주기(Scope) 방식이 변경되었어요. 이전 버전에서는 루프 안의 변수를 공유했지만, 이제는 매 반복마다 새로운 변수가 생성되어 더 안전하게 사용할 수 있답니다.
실전에서 바로 쓰는 Go 반복문 핵심 패턴
이제 이론은 충분해요. 실제 개발 환경에서 가장 자주 쓰이는 패턴들을 단계별로 살펴볼게요. 각 단계의 코드를 눈으로만 보지 말고, 직접 타이핑하며 흐름을 느껴보는 것이 가장 빠르게 배우는 방법이에요.
STEP 1. 가장 기본적인 3단계 제어 방식
우리가 흔히 아는 가장 고전적인 방식이에요. 세미콜론(;)을 기준으로 세 가지 요소를 정의해요. 이 방식은 인덱스를 세밀하게 조정해야 할 때 아주 유용해요. 예를 들어, 2칸씩 건너뛰며 확인해야 하거나, 인덱스를 거꾸로 뒤집어야 할 때 사용하죠.
먼저, 0부터 9까지 숫자를 출력하는 기본 구조를 볼게요. 초기화 식에서 변수를 선언하고, 조건식이 참인 동안 실행되며, 증감 식을 통해 다음 단계로 넘어가요. 이 세 요소 중 하나를 생략할 수도 있지만, 구조를 명확히 지키는 것이 나중에 코드를 읽을 동료를 위한 배려예요.
STEP 2. 조건만으로 제어하는 while 스타일
Go에는 while이라는 단어가 없지만, for 문에 조건식 하나만 적어주면 바로 while 문이 돼요. 특정 상태값이 바뀔 때까지 계속 실행해야 하는 작업, 예를 들어 네트워크 연결이 성공할 때까지 재시도하거나, 큐(Queue)에 데이터가 남아있는 동안 계속 꺼내올 때 이 방식을 써요.
만약 아무런 조건도 적지 않고 for { ... } 처럼 사용하면 무한 루프가 돼요. 이때 반드시 내부에서 break 키워드를 사용해 탈출구를 만들어줘야 해요. 탈출 조건이 명확하지 않으면 서버 전체가 멈추는 사고로 이어질 수 있으니 정말 주의해야 해요.
STEP 3. range를 이용한 스마트한 컬렉션 순회
실무에서 가장 많이 쓰는 패턴은 단연 range 키워드예요. 슬라이스(Slice)나 배열, 맵(Map) 같은 데이터를 다룰 때 인덱스를 일일이 계산할 필요 없이 아주 깔끔하게 코드를 짤 수 있게 도와줘요.
슬라이스를 순회할 때 range는 두 가지 값을 반환해요. 하나는 현재 요소의 번호인 인덱스이고, 다른 하나는 그 칸에 들어있는 값이에요. 만약 인덱스가 필요 없다면 언더바(_)를 사용해 무시할 수 있어요. 이는 Go의 아주 독특하고 강력한 문법이에요.
맵(Map)을 range로 순회할 때는 주의할 점이 있어요. 맵은 순서가 보장되지 않는 자료구조예요. 즉, 똑같은 코드를 실행해도 매번 출력되는 순서가 달라질 수 있다는 뜻이죠. 순서가 중요하다면 키(Key)를 따로 추출해서 정렬한 뒤 순회해야 해요.
STEP 4. 실전 시나리오: 데이터 필터링 작업
이해를 돕기 위해 실제 상황을 가정해 볼게요. 고객 명단(슬라이스) 중에서 나이가 20세 이상인 성인만 골라내는 작업을 수행한다고 해봅시다. 이 과정에서 우리는 조건을 체크하고, 조건에 맞는 데이터만 새로운 리스트에 담는 과정을 반복하게 됩니다.
이런 작업은 range를 사용하여 아주 간결하게 구현할 수 있어요. 각 고객 객체를 하나씩 꺼내어 나이 필드를 확인하고, 조건에 맞으면 결과를 모으는 방식이죠. 이때 리스트의 길이를 미리 알 수 없다면 append 함수를 적절히 활용하는 것이 핵심이에요.
STEP 5. 중첩 루프와 성능 최적화
가끔 루프 안에 또 다른 루프가 들어가는 중첩 구조를 사용해야 할 때가 있어요. 예를 들어, 2차원 행렬 데이터를 처리하거나, 여러 명의 사용자별로 그들이 가진 아이템 목록을 확인할 때 말이죠. 하지만 중첩 루프는 데이터 양이 늘어남에 따라 실행 시간이 기하급수적으로 늘어나는 시간 복잡도 문제를 일으킬 수 있어요.
중첩 루프를 쓸 때는 항상 생각해야 해요. ‘이 작업을 루프를 겹치지 않고 풀 수 있는 방법은 없을까?’ 예를 들어, 맵을 활용해 미리 데이터를 정리해 두면 중첩 루프를 단일 루프로 줄여 성능을 획기적으로 높일 수 있는 경우가 많아요. 실무에서는 성능 최적화가 매우 중요하므로 이 부분을 늘 염두에 두어야 해요.
자주 하는 실수와 해결법
실력이 늘수록 실수도 다양해지기 마련이죠. 경험 많은 개발자들도 무의식중에 저지르는 실수들을 모아봤어요. 비슷한 문제를 겪고 있다면 아래 내용을 확인해 보세요.
- ❌ 인덱스 범위 초과 (Out of Bounds)
왜 발생하는가: 슬라이스의 길이를len(s)로 잡지 않고len(s) + 1로 설정하는 경우 발생해요.
✅ 해결법: 반복문의 조건식을 항상i < len(s)와 같이 미만 연산자를 사용하도록 설정하세요. - ❌ 무한 루프 발생
왜 발생하는가: 탈출 조건(break)이 실행되지 않는 경로로 로직이 짜였을 때 발생해요.
✅ 해결법: 루프가 종료되는 조건을 시각적으로 먼저 설계하고, 루프 내부에서 해당 조건이 반드시 갱신되는지 확인하세요. - ❌ 맵 순회 순서의 불일치
왜 발생하는가: 맵은 순서가 없는데, 루프를 돌 때마다 결과가 달라져 테스트가 실패하는 경우예요.
✅ 해결법: 정렬된 키 리스트를 만든 뒤, 그 리스트를 기반으로 맵을 조회하며 순회하세요. - ❌ 루프 변수 포인터 캡처 오류
왜 발생하는가: 루프 안에서 생성된 변수의 주소값을 슬라이스나 채널에 담을 때, 모든 요소가 마지막 값만 가리키는 현상이에요.
✅ 해결법: Go 1.22 이상을 사용하거나, 루프 내부에서 새로운 지역 변수를 선언해 값을 복사해 두어야 해요. - ❌ 불필요한 할당 작업
왜 발생하는가: 루프 안에서 매번 커다란 객체를 새로 생성하여 메모리 압박을 주는 경우예요.
✅ 해결법: 가능하면 루프 밖에서 변수를 미리 선언하고, 루프 안에서는 값만 업데이트하여 재사용하세요.
자주 묻는 질문
Q. Go에서 while 문은 정말 따로 없나요?
네, 맞아요. 대신 for 조건식 { ... } 형태를 사용하면 우리가 원하는 while 문과 완벽하게 동일하게 작동해요. 구조를 하나로 통일한 Go의 철학이라고 보시면 돼요.
Q. range를 쓸 때 인덱스가 필요 없으면 어떻게 하나요?
그럴 때는 for _, value := range slice와 같이 언더바(_)를 사용해 보세요. 언더바는 '이 값은 받겠지만 사용하지 않겠다'는 것을 컴파일러에게 알려주는 아주 유용한 기호예요.
Q. for 루프를 중간에 멈추고 싶을 때는 어떻게 하나요?break를 사용하면 즉시 루프를 빠져나올 수 있고, continue를 사용하면 현재 차례만 건너뛰고 다음 반복으로 바로 넘어갈 수 있어요.
Q. 루프 성능을 높이는 가장 쉬운 방법은 무엇인가요?
슬라이스에 데이터를 추가할 때 append를 너무 많이 사용한다면, 미리 make 함수로 적절한 용량(capacity)을 할당해 두는 것만으로도 성능이 크게 좋아져요.
핵심 요약과 다음 단계
오늘 배운 내용을 잊지 않도록 마지막으로 한 번 더 정리해 볼게요. 이 내용만 기억해도 실무 코드의 안정성이 훨씬 높아질 거예요.
- Go의 반복문은 오직
for하나로 모든 것을 해결해요. range를 활용하면 슬라이스와 맵을 아주 쉽고 안전하게 순회할 수 있어요.- 맵을 순회할 때는 결과의 순서가 매번 바뀔 수 있다는 점을 꼭 기억하세요.
- 무한 루프를 방지하기 위해
break탈출 조건을 명확히 설정해야 해요. - 인덱스 범위를 벗어나지 않도록
len()함수를 적극 활용하세요.
이제 이론은 끝났어요. 직접 코드를 쳐볼 시간이에요!
오늘 바로 실천할 일
- 본인의 컴퓨터에 Go 환경을 세팅하고 간단한
for문 예제 3개를 직접 실행해 보세요. - 슬라이스를 만들고
range를 사용하여 모든 요소를 출력하는 코드를 작성해 보세요.
이번 주 도전 과제
간단한 성적 관리 프로그램을 만들어 보세요. 학생들의 점수가 담긴 슬라이스를 만들고, 반복문을 사용해 평균 점수를 계산하며, 60점 미만인 학생만 골라내는 로직을 구현해 보는 거예요. 이 과정을 마치면 반복문에 대한 감각이 확실히 달라져 있을 거예요.
혹시 코드를 작성하다가 막히는 부분이 있거나 이해가 안 되는 개념이 있다면 언제든 댓글로 남겨 주세요. 제가 확인하는 대로 친절하게 답변해 드릴게요. 함께 성장해 나가요!
함께 읽으면 좋은 글: Go 반복문 완벽 가이드