
반복문 제어의 어려움, Go에서는 어떻게 해결할까요?
새로운 프로그래밍 언어를 배울 때 가장 당혹스러운 순간 중 하나는 익숙했던 문법이 보이지 않을 때예요. 다른 언어에서는 당연하게 사용하던 while이나 do-while 같은 키워드가 Go 언어에는 존재하지 않기 때문이죠. 루프를 돌리려고 문법 책을 펼쳤는데 오직 for 하나만 적혀 있는 것을 보고 당황한 경험이 있으신가요?
단순히 반복 횟수를 지정하는 것을 넘어, 슬라이스의 요소를 하나씩 꺼내거나 맵(Map)의 키와 값을 매칭하는 작업은 실무 프로그래밍의 핵심이에요. 하지만 Go의 for는 매우 강력한 만큼, 처음 접하는 입문자에게는 그 활용법이 다소 막연하게 느껴질 수 있어요. 조건식을 어떻게 설정해야 무한 루프에 빠지지 않는지, 혹은 range를 사용할 때 왜 인덱스와 값이 함께 나오는지 이해하는 것이 첫 번째 과제예요.
이 글을 끝까지 읽고 나면 여러분은 더 이상 반복문 때문에 코드를 헤매지 않게 될 거예요. 복잡한 비즈니스 로직 속에서도 효율적으로 데이터를 순회하고, 실수 없이 루프를 제어하는 능력을 갖추게 됩니다. Go 반복문 치트시트를 통해 실전에서 바로 써먹을 수 있는 핵심 기술들을 완벽하게 내 것으로 만들어 보세요.
이 가이드에서 여러분은 다음 내용들을 확실히 배우게 돼요.
- Go 언어만의 독특한 for 문법 구조와 활용 방식
- 슬라이스, 맵, 문자열을 가장 효율적으로 순회하는 방법
- 실무에서 자주 발생하는 반복문 오류와 해결 전략
- 코드의 가독성을 높여주는 고급 제어 패턴
반복문을 시작하기 전 반드시 알아야 할 기본 원리
Go 언어의 가장 큰 특징 중 하나는 언어의 단순함이에요. 다른 언어들이 여러 종류의 반복문을 제공하는 것과 달리, Go는 오직 for 키워드 하나로 모든 반복 로직을 처리해요. 이는 언어의 복잡도를 낮추고 코드의 일관성을 높여주지만, 반대로 말하면 for 하나에 담긴 다양한 변형 형태를 정확히 숙지해야 한다는 뜻이기도 해요.
본격적인 코딩에 들어가기 전에, 여러분이 어떤 상황에서 어떤 형태의 반복문을 선택해야 할지 판단 기준을 세워야 해요. 무작정 코드를 치기보다는 상황에 맞는 최적의 구조를 선택하는 것이 Golang 개발자의 기본 소양이에요.
반복문 형태별 비교 및 선택 기준
상황에 따라 적절한 반복 방식을 선택할 수 있도록 아래 표를 참고해 보세요.
| 구분 방식 | 주요 특징 | 추천 사용 상황 |
|---|---|---|
| 표준형 (C-style) | 초기값, 조건식, 증감식을 명시함 | 정해진 횟수만큼 반복할 때 |
| 조건식 중심 (While-style) | 조건이 참인 동안 계속 실행됨 | 종료 시점이 불명확할 때 |
| 범위 순회 (Range-style) | 컬렉션의 요소를 하나씩 꺼냄 | 슬라이스나 맵을 전부 훑을 때 |
| 무한 루프 (Infinite) | 조건식 없이 무한히 실행됨 | 내부에서 break로 탈출할 때 |
Go에는 while 키워드가 따로 없어요. 하지만 for
반복문을 작성할 때 가장 주의해야 할 점은 탈출 조건의 명확성이에요. 조건식이 항상 참(true)이 되어 버리면 프로그램은 멈추지 않고 메모리를 계속 잡아먹는 무한 루프에 빠지게 돼요. 특히 복잡한 로직 안에서 상태 값을 변경할 때, 그 값이 조건식에 어떻게 영향을 미치는지 반드시 눈으로 확인하는 습관을 들여야 해요.
실전 Go 반복문 활용 가이드: 핵심 패턴 5단계
이제 이론을 넘어 실제 코드로 어떻게 반복문을 구현하는지 구체적으로 살펴볼게요. Go의 반복문은 매우 직관적이지만, 각 단계별로 미세한 차이가 결과의 효율성을 결정지어요. 실전에서 바로 복사해서 사용할 수 있을 만큼 상세한 예제와 설명을 준비했어요.
STEP 1. 표준형 반복문: 정해진 횟수 제어하기
가장 기본이 되는 형태예요. 주로 숫자를 카운트하거나 특정 횟수만큼 로직을 반복해야 할 때 사용해요. 세 가지 구성 요소인 초기화, 조건식, 증감식이 한 줄에 들어가는 것이 특징이에요.
초기값이나 증감식은 생략이 가능해요. 생략하면 더 유연한 루프를 만들 수 있어요.
예를 들어, 1부터 5까지 출력하는 코드는 다음과 같아요.
for i := 1; i <= 5; i++ {
fmt.Println(i)
}
여기서 i := 1은 시작점, i <= 5는 언제까지 돌지 결정하는 기준, i++는 한 번 돌 때마다 어떻게 변화할지를 나타내요. 이 세 가지 중 하나라도 빼면 문법 오류가 나는 것이 아니라, 다른 형태의 반복문으로 변신하게 되는 것이 Go의 묘미예요.
STEP 2. 조건식 중심 반복문: While 스타일 구현
종료 시점이 명확한 숫자가 아니라, 특정 조건이 만족되는 동안 계속 실행되어야 한다면 이 방식을 사용해요. 다른 언어의 while 루프와 똑같은 역할을 수행하죠.
isRunning := true
for isRunning {
// 어떤 작업 수행...
if someCondition {
isRunning = false // 조건 변경으로 루프 종료
}
}
이 방식에서는 루프 내부에서 반드시 isRunning과 같은 조건 변수의 상태를 변화시켜줘야 해요. 그렇지 않으면 프로그램이 영원히 멈추지 않는 대참사가 발생할 수 있어요. 탈출 조건을 설계할 때 항상 ‘언제 멈추는가’를 먼저 생각하세요.
STEP 3. Range 반복문: 컬렉션 데이터 완벽 순회
실무에서 가장 많이 쓰이는 형태예요. 슬라이스(Slice), 배열(Array), 맵(Map), 문자열(String) 같은 데이터 꾸러미를 하나씩 꺼낼 때 사용해요. range 키워드를 쓰면 인덱스와 실제 값을 동시에 얻을 수 있어 매우 편리해요.
1) 슬라이스 순회:
슬라이스의 인덱스와 값을 모두 가져와요.numbers := []int{10, 20, 30}
for index, value := range numbers {
fmt.Printf("인덱스: %d, 값: %d\n", index, value)
}
2) 맵(Map) 순회:
맵은 키(Key)와 값(Value)의 쌍으로 이루어져 있어요.userAges := map[string]int{"Kim": 25, "Lee": 30}
for name, age := range userAges {
fmt.Printf("%s의 나이는 %d살이에요.\n", name, age)
}
주의할 점: 맵은 순회할 때마다 순서가 무작위로 바뀔 수 있어요! 데이터가 항상 같은 순서로 나올 것이라고 기대하면 안 돼요.
3) 문자열 순회:
문자열을 range로 돌리면 바이트(Byte)가 아닌 룬(Rune, Unicode 코드 포인트) 단위로 가져와요. 덕분에 한글 같은 멀티바이트 문자도 깨지지 않고 안전하게 처리할 수 있어요.
STEP 4. 제어 문구: Break와 Continue 활용
루프의 흐름을 능동적으로 조절하고 싶을 때 break와 continue를 사용해요.
- break: 루프를 즉시 완전히 종료하고 빠져나와요. 특정 값을 찾았을 때 더 이상 돌 필요가 없는 경우에 유용해요.
- continue: 현재 차례의 남은 코드를 건너뛰고 바로 다음 반복으로 넘어가요. 특정 조건을 만족하는 데이터만 제외하고 싶을 때 사용해요.
만약 중첩된 루프(루프 안에 루프가 있는 경우)에서 바깥쪽 루프까지 한 번에 탈출하고 싶다면 Label을 사용해야 해요. 이는 코드의 복잡도를 높일 수 있으니 꼭 필요한 경우에만 신중하게 사용하세요.
STEP 5. 실전 시나리오: 데이터 필터링 및 계산
그럼 지금까지 배운 내용을 종합해서 실제 프로덕션 환경에서 사용될 법한 시나리오를 구성해 볼게요. 사용자 목록에서 특정 나이 이상의 사람을 찾아 평균 나이를 계산하는 로직이에요.
type User struct {
Name string
Age int
}
func main() {
users := []User{
{Name: "Kim", Age: 25},
{Name: "Lee", Age: 35},
{Name: "Park", Age: 40},
{Name: "Choi", Age: 18},
}
totalAge := 0
count := 0
// 20세 이상인 사용자만 필터링하여 합산
for _, user := range users {
if user.Age < 20 {
continue // 20세 미만은 건너뜀
}
totalAge += user.Age
count++
}
if count > 0 {
avg := float64(totalAge) / float64(count)
fmt.Printf("성인 평균 나이: %.2f\n", avg)
}
}
이 예제에서는 range를 사용해 구조체 슬라이스를 순회했고, continue를 사용해 조건에 맞지 않는 데이터를 효율적으로 걸러냈어요. 이런 패턴이 모여 실제 서비스의 핵심 로직이 됩니다.
자주 하는 실수와 해결법 + FAQ
코드를 짜다 보면 누구나 실수를 해요. 특히 반복문은 잘못 작성했을 때 프로그램이 멈추지 않거나 엉뚱한 데이터를 처리하는 치명적인 버그를 유발할 수 있어요. 자주 마주치는 문제들을 정리해 두었으니 꼭 기억해 두세요.
자주 하는 실수와 해결법
- ❌ 실수: 슬라이스 인덱스 범위 초과 (Out of bounds)
왜 발생하는가: i <= len(slice)처럼 조건식에 등호를 잘못 넣어 마지막 인덱스를 넘어가는 경우예요.
✅ 해결법: 항상 i < len(slice)를 사용하거나, 가급적 range를 사용해 인덱스 관리를 자동화하세요. - ❌ 실수: 루프 내에서 슬라이스 요소 수정하기
왜 발생하는가: range로 가져온 값은 원본의 ‘복사본’인 경우가 많아요. 값을 바꿨는데 원본 슬라이스가 변하지 않아 당황할 수 있어요.
✅ 해결법: 원본을 수정해야 한다면 인덱스를 사용해 slice[i] = newValue 방식으로 직접 접근하세요. - ❌ 실수: 무한 루프의 늪
왜 발생하는가: while 스타일의 루프에서 조건을 변화시키는 로직을 빠뜨린 경우예요.
✅ 해결법: 루프가 시작되기 전, 탈출 조건이 반드시 충족될 수 있는 경로가 있는지 코드 흐름을 따라가며 검증하세요. - ❌ 실수: 맵(Map) 순회 순서 오해
왜 발생하는가: 맵을 돌릴 때 항상 같은 순서로 데이터가 나올 것이라 믿고 특정 인덱스에 의존하는 경우예요.
✅ 해결법: 순서가 중요하다면 데이터를 별도의 슬라이스에 담아 정렬한 뒤 순회하세요. - ❌ 실수: 고루틴(Goroutine) 내 루프 변수 공유
왜 발생하는가: (Go 1.22 이전 버전 기준) 루프 변수를 고루틴 안에서 바로 쓰면 모든 고루틴이 마지막 값만 참조하는 현상이 발생해요.
✅ 해결법: 최신 Go 버전을 사용하거나, 루프 내부에서 변수를 지역 변수로 재선언해 값을 고정하세요.
자주 묻는 질문
Q. Go에서 while 문을 쓰고 싶은데 방법이 없나요?
방법은 아주 간단해요! for
Q. range를 쓸 때 인덱스가 필요 없으면 어떻게 하나요?
인덱스 대신 언더스코어(_)를 사용하면 돼요. for _, value := range slice처럼 작성하면 인덱스는 무시하고 값만 가져올 수 있어요.
Q. 반복문을 거꾸로(역순으로) 돌리고 싶어요.
표준형 반복문을 활용해야 해요. for i := len(slice) – 1; i >= 0; i–와 같이 초기값과 증감식을 역방향으로 설정하면 돼요.
Q. break와 continue의 차이가 정확히 무엇인가요?
break는 루프 자체를 ‘탈출’해서 완전히 끝내는 것이고, continue는 현재 차례만 ‘건너뛰고’ 다음 차례로 바로 넘어가는 것이에요.
Q. 문자열을 range로 돌릴 때 왜 숫자가 이상하게 나오나요?
문자열은 바이트의 집합이에요. range는 문자를 Unicode(Rune) 단위로 읽기 때문에, 출력 형식을 %d가 아닌 %c(문자)로 지정해야 제대로 된 글자가 보여요.
반복문 마스터를 위한 마지막 체크리스트
오늘 배운 내용을 바탕으로 여러분의 코드를 다시 한번 점검해 보세요. 반복문은 단순해 보이지만, 어떻게 쓰느냐에 따라 프로그램의 안정성과 성능이 천차만별로 달라져요.
- for 하나로 통일: Go에는 while이나 do-while이 없으니 for의 변형 형태를 익히세요.
- range 적극 활용: 슬라이스나 맵을 다룰 때는 인덱스 실수 방지를 위해 range를 우선 고려하세요.
- 탈출 조건 확인: 무한 루프를 방지하기 위해 조건식의 변화를 반드시 체크하세요.
- 맵 순서 주의: 맵 순회는 무작위성이 있으므로 정렬이 필요하면 별도 처리를 하세요.
- 문자열은 Rune 단위로: 한글 처리를 위해 문자열 순회 시 range를 사용하세요.
이제 이론은 끝났어요. 다음 단계로 나아가기 위해 오늘 바로 실천할 수 있는 과제를 드릴게요.
오늘 바로 실행할 일
- 자신이 작성했던 코드 중 for 문이 있는 부분을 찾아 range로 바꿀 수 있는지 확인해 보세요.
- 슬라이스에 10개의 숫자를 넣고, 짝수만 출력하는 간단한 코드를 직접 작성해 보세요.
이번 주 목표
- 맵(Map) 데이터를 무작위 순서가 아닌, 키(Key) 기준으로 정렬하여 출력하는 로직을 구현해 보세요.
Go 프로그래밍의 세계는 넓고 배울 것이 많아요. 반복문을 정복했다면, 이제 데이터 구조와 제어 흐름에 대해 더 깊이 파고들 준비가 된 거예요. 공부하다가 막히는 부분이 있거나 예제 코드가 동작하지 않는다면 언제든 댓글로 남겨 주세요. 여러분의 성장을 진심으로 응원할게요!
함께 읽으면 좋은 글: Go 반복문 완벽 가이드