
왜 Go의 반복문 하나만 제대로 알아야 할까요
다른 프로그래밍 언어를 공부하다가 Go(Golang)로 넘어오면 가장 먼저 당황하게 되는 지점이 있어요. 바로 while 문이나 do-while 문이 보이지 않는다는 사실이에요. 파이썬이나 자바에서는 조건에 따라 반복하는 문법이 따로 있지만, Go는 오직 for 문 하나로 이 모든 것을 해결해요.
처음에는 “어떻게 문법 하나로 이 많은 걸 다 처리하지?”라는 의구심이 들 수도 있어요. 하지만 이는 Go의 철학인 단순함과 명확성을 보여주는 아주 중요한 특징이에요. 문법이 단순하다는 것은 읽기 쉽고, 실수할 확률이 줄어든다는 뜻이기도 하죠.
이 글을 끝까지 읽고 나면 여러분은 복잡한 반복 로직을 만났을 때 당황하지 않고, 가장 효율적인 Go 스타일의 반복문을 선택할 수 있게 돼요. 단순한 문법 암기를 넘어, 어떤 상황에서 어떤 패턴을 써야 성능과 가독성을 모두 잡을 수 있는지 실전 감각을 익히게 될 거예요.
- Go 반복문의 기본 3요소와 구조 이해하기
- 슬라이스와 맵을 위한 range 활용법
- 조건부 반복과 무한 루프 제어하기
- 실전에서 자주 마주치는 실수와 해결책
반복문을 시작하기 전 꼭 알아야 할 기초 지식
Go의 반복문을 제대로 다루기 위해서는 단순히 문법을 외우는 것보다 데이터의 구조를 먼저 이해하는 것이 훨씬 중요해요. 반복문은 결국 데이터 뭉치를 하나씩 꺼내서 처리하는 과정이기 때문이에요.
가장 먼저 준비해야 할 것은 Go의 기본 데이터 타입이에요. 특히 여러 개의 값을 담는 슬라이스(Slice)와 키-값 쌍으로 이루어진 맵(Map)의 구조를 모르면, 반복문을 돌릴 때 인덱스 오류를 내기 십상이에요. 또한, Go의 for 문은 세 가지 구성 요소를 가질 수 있다는 점을 기억하세요.
- 초기화 문(Init): 반복이 시작될 때 변수를 설정해요.
- 조건식(Condition): 이 조건이 참(true)인 동안에만 계속 반복해요.
- 후처리 문(Post): 한 번의 반복이 끝날 때마다 실행되는 동작이에요.
상황에 따라 어떤 형태의 반복문을 선택해야 할지 고민될 때는 아래 비교 표를 참고해 보세요. 각 방식의 특징을 파악하면 코드를 작성하는 속도가 훨씬 빨라져요.
| 반복 방식 | 주요 용도 | 장점 |
|---|---|---|
| 표준 for 문 | 정해진 횟수만큼 반복할 때 | 인덱스 제어가 매우 정교함 |
| for range 문 | 슬라이스나 맵의 요소를 순회할 때 | 코드가 간결하고 가독성이 높음 |
| 조건식 전용 루프 | 특정 조건이 충족될 때까지 반복 | while 문처럼 유연하게 사용 가능 |
| 무한 루프 | 특정 이벤트가 발생할 때까지 대기 | 서버 리스너 등 지속적 작업에 적합 |
준비가 되셨나요? 이제 본격적으로 Go 반복문의 실전 패턴을 하나씩 살펴볼게요. 처음에는 복잡해 보일 수 있지만, 몇 가지 예제만 직접 따라 해보면 금방 익숙해질 수 있어요.
실전 Go 반복문 마스터하기
이제 본격적으로 현업에서 바로 사용할 수 있는 단계별 반복문 패턴을 배워볼게요. 각 단계는 단순한 문법 설명을 넘어, 실제 어떤 상황에서 쓰이는지에 집중했어요.
STEP 1. 표준 for 문으로 정밀하게 제어하기
가장 기본적인 형태의 반복문이에요. 숫자를 하나씩 세거나, 특정 간격으로 데이터를 건너뛰어야 할 때 사용해요. C 언어나 Java 스타일과 매우 유사해서 익숙하실 거예요.
표준 for 문은 인덱스 변수를 직접 조작할 수 있다는 점이 가장 큰 특징이에요. 2씩 증가시키거나, 역순으로 숫자를 줄이는 작업도 아주 자유로워요.
예를 들어, 0부터 9까지 2씩 건너뛰며 출력하고 싶다면 이렇게 작성하면 돼요.
for i := 0; i < 10; i += 2 {
fmt.Println(i)
}
이 방식은 루프의 시작점, 끝점, 변화량을 한 줄에서 모두 관리할 수 있어 흐름을 파악하기 아주 좋답니다.
STEP 2. for range를 이용한 데이터 순회
Go 개발자들이 가장 많이 사용하는 방식이에요. 슬라이스(Slice)나 배열, 맵(Map) 같은 컬렉션을 다룰 때, 인덱스를 직접 계산할 필요 없이 아주 깔끔하게 요소를 꺼낼 수 있어요.
슬라이스를 순회할 때는 보통 인덱스와 값을 동시에 받을 수 있어요. 만약 인덱스는 필요 없고 값만 필요하다면, 빈 식별자(blank identifier)인 _를 사용해서 무시하면 돼요.
fruits := []string{"사과", "바나나", "포도"}
for i, fruit := range fruits {
fmt.Printf("%d번째 과일: %s\n", i, fruit)
}
주의할 점은 맵(Map)을 순회할 때는 순서가 보장되지 않는다는 것이에요. 똑같은 코드를 실행해도 매번 결과 순서가 바뀔 수 있으니, 순서가 중요하다면 별도의 정렬 과정을 거쳐야 해요.
STEP 3. 조건식만 사용하는 유연한 루프
Go에는 while 문이 따로 없어요. 대신 for 키워드 뒤에 조건식만 적어주면 우리가 원하는 while 문과 똑같이 동작해요. 어떤 조건이 참인 동안 계속해서 작업을 수행해야 할 때 아주 유용하죠.
count := 1
for count <= 5 {
fmt.Println("현재 숫자:", count)
count++
}
이 패턴은 파일의 끝(EOF)에 도달할 때까지 데이터를 읽거나, 네트워크 연결이 유지되는 동안 계속해서 메시지를 수신하는 서버 로직에서 정말 자주 쓰여요.
STEP 4. break와 continue로 흐름 제어하기
반복문을 돌다가 중간에 멈춰야 하거나, 특정 조건에서 이번 차례만 건너뛰고 싶을 때가 있죠? 이때 사용하는 것이 break와 continue예요.
- break: 반복문을 즉시 종료하고 루프 밖으로 빠져나가요.
- continue: 현재 진행 중인 차례를 중단하고 바로 다음 반복으로 넘어가요.
예를 들어, 숫자를 1부터 10까지 출력하되 5는 건너뛰고, 8이 되면 아예 멈추고 싶다면 다음과 같이 작성할 수 있어요.
for i := 1; i <= 10; i++ {
if i == 5 {
continue // 5는 건너뜁니다
}
if i == 8 {
break // 8이 되면 종료합니다
}
fmt.Println(i)
}
STEP 5. 실전 시나리오: 사용자 목록 데이터 처리하기
이제 배운 것들을 하나로 묶어서 실제 실무에서 마주할 법한 코드를 짜볼게요. 사용자 정보를 담은 구조체 슬라이스가 있고, 그중에서 특정 등급 이상의 사용자만 골라내어 메시지를 출력하는 시나리오예요.
type User struct {
Name string
Level int
}
func main() {
users := []User{
{"김철수", 1},
{"이영희", 5},
{"박민수", 3},
{"최지우", 8},
}
fmt.Println("--- VIP 사용자 명단 ---")
for _, user := range users {
if user.Level >= 5 {
fmt.Printf("명단 추가: %s (레벨: %d)\n", user.Name, user.Level)
}
}
}
이처럼 range로 데이터를 훑으면서 if 문으로 조건을 필터링하는 패턴은 Go 프로그래밍의 가장 기초적이면서도 강력한 무기가 된답니다.
자주 하는 실수와 해결법 및 FAQ
반복문을 처음 다룰 때 누구나 한 번쯤은 겪게 되는 시행착오들이 있어요. 이런 실수들만 미리 알아두어도 디버깅 시간을 획기적으로 줄일 수 있어요.
자주 하는 실수와 해결법
❌ 인덱스 범위를 벗어나는 오류 (Index out of range)
왜 발생하는가: 슬라이스의 길이를 잘못 계산하거나, 조건식에서 i <= len(slice)처럼 등호를 잘못 붙여 마지막 인덱스 너머를 참조할 때 발생해요.
✅ 해결법: 항상 i < len(slice) 형식을 사용하고, 가급적 인덱스 계산이 필요 없는 for range 문을 사용하세요.
❌ 무한 루프에 빠지는 상황
왜 발생하는가: 조건식이 항상 참(true)이거나, 반복문 내부에서 조건식을 변화시키는 변수(예: i++)를 업데이트하는 것을 깜빡했을 때 발생해요.
✅ 해결법: 루프가 끝나는 지점을 명확히 설정하고, 반복문 실행 시마다 조건에 영향을 주는 변수가 변하는지 반드시 확인하세요.
❌ range 문에서의 변수 값 덮어쓰기 (Shadowing)
왜 발생하는가: for i, v := range slice를 사용할 때, v는 매 반복마다 새로운 복사본이 생성돼요. 이 변수의 주소값을 가져와서 나중에 쓰려고 하면 모두 같은 값을 가리키게 될 수 있어요.
✅ 해결법: 슬라이스의 요소 자체를 수정해야 한다면, 값(v) 대신 인덱스(i)를 사용해 slice[i] 방식으로 직접 접근하세요.
❌ 맵(Map) 순회 시 일관성 없는 순서
왜 발생하는가: Go의 맵은 순서가 정해져 있지 않아요. 반복문을 돌릴 때마다 결과가 달라지는 것은 오류가 아니라 Go의 설계 원칙이에요.
✅ 해결법: 결과 순서가 중요하다면 맵의 키들을 별도의 슬라이스에 담아 정렬한 뒤, 그 정렬된 키를 이용해 맵을 순회하세요.
자주 묻는 질문
Q. Go에서 while 문을 쓰고 싶은데 어떻게 해야 하나요?
A. Go에는 별도의 while 문이 없어요. 대신 for 조건식 { ... } 형태를 사용하면 우리가 흔히 아는 while 문과 똑같이 작동해요.
Q. range 문에서 인덱스가 필요 없으면 어떻게 처리하나요?
A. 빈 식별자인 언더스코어(_)를 사용하면 돼요. for _, value := range slice와 같이 작성하면 인덱스는 무시하고 값만 가져올 수 있어요.
Q. 무한 루프를 만드는 가장 깔끔한 방법은 무엇인가요?
A. 조건식 없이 for { ... }라고만 적으면 돼요. 이 루프 안에서 특정 조건이 되면 break를 호출하여 탈출하는 구조로 가장 많이 사용해요.
Q. 슬라이스를 순회하면서 요소를 삭제해도 안전한가요?
A. 조심해야 해요! 반복문 도중에 슬라이스의 길이를 바꾸면 인덱스가 꼬여서 원하는 대로 동작하지 않거나 에러가 날 수 있어요. 요소를 삭제해야 한다면 역순으로 반복문을 돌리거나, 새로운 슬라이스를 만드는 방식을 추천해요.
반복문 정복을 위한 마무리 가이드
지금까지 Go 언어의 유일한 반복문인 for 문의 모든 것을 살펴보았어요. 처음에는 문법이 단순해서 부족해 보일 수 있지만, 익숙해지면 이보다 더 명확하고 강력한 도구는 없다는 걸 느끼게 될 거예요.
- Go에는 for 문 하나로 모든 반복(while, for)을 처리해요.
- 정밀한 제어가 필요할 땐 표준 for 문을 사용하세요.
- 슬라이스나 맵을 순회할 땐 가독성이 좋은 range 문이 최고예요.
- break와 continue로 루프의 흐름을 자유롭게 조절하세요.
- 맵 순회 시 순서가 바뀌는 것은 정상적인 동작임을 기억하세요.
- 인덱스 에러를 피하려면 range 문 사용을 습관화하세요.
이제 이론은 충분해요. 직접 코드를 타이핑해 보는 것만큼 빠른 학습법은 없답니다. 오늘 배운 내용을 바탕으로 아래 단계들을 하나씩 실행해 보세요.
- 오늘 할 일: Go Playground(play.golang.org)에 접속해서 위 예제 코드들을 하나씩 복사해서 실행해 보기
- 이번 주 할 일: 슬라이스에 담긴 숫자들의 평균을 구하거나, 특정 조건을 만족하는 요소만 필터링하는 작은 연습 문제 풀어보기
- 실행 직전 할 일:
for range를 사용할 때 인덱스가 필요한지, 값만 필요한지 스스로 결정해 보기
Go 프로그래밍의 기초를 탄탄히 다지고 싶다면, 다음 가이드인 Go 반복문 완전 정복 가이드를 함께 읽어 보시는 것을 추천드려요. 더 깊이 있는 내부 동작 원리까지 이해할 수 있습니다.
공부하시다가 막히는 부분이 있거나 이해가 안 되는 코드 패턴이 있다면 언제든 댓글로 질문을 남겨 주세요. 여러분의 성장을 진심으로 응원합니다!