
반복문 하나로 끝내는 Go 프로그래밍의 매력
파이썬(Python)이나 자바(Java)를 먼저 공부했던 분들이 Go 언어를 처음 마주하면 가장 당황하는 순간이 있어요. 바로 반복문 키워드가 딱 하나뿐이라는 사실을 알게 되었을 때예요. 보통 다른 언어에서는 조건에 따라 while을 쓰거나, 집합을 돌릴 때 foreach를 사용하는 식으로 구분해서 사용하잖아요?
하지만 Go는 오직 for라는 키워드 하나로 모든 반복 로직을 처리해요. 처음에는 “왜 이렇게 단순할까?”라는 의문이 들 수도 있지만, 익숙해지면 오히려 문법이 단순해져서 코드를 읽는 속도가 비약적으로 빨라지는 것을 경험할 수 있어요.
반복문을 잘못 사용하면 무한 루프에 빠져 프로그램이 멈추거나, 메모리를 과도하게 잡아먹는 실수를 저지르기 쉬워요. 특히 Go는 병렬 처리가 강력한 언어인 만큼, 반복문 안에서 고루틴(Goroutine)을 잘못 다루면 예측하기 힘든 버그가 발생하기도 해요. 그래서 기초를 탄탄하게 다지는 것이 무엇보다 중요해요.
이 글을 끝까지 읽고 나면 다음과 같은 능력을 갖추게 돼요.
- Go의 다양한 for 문법을 상황에 맞춰 자유자재로 선택할 수 있어요.
- 슬라이스(Slice)나 맵(Map)을 효율적으로 순회하는 방법을 익혀요.
- 실무에서 자주 발생하는 반복문 관련 실수와 그 해결책을 완벽히 이해해요.
효율적인 반복을 위한 사전 지식과 기준
반복문을 작성하기 전에 먼저 Go의 for 문이 가진 구조적 특징을 이해해야 해요. Go의 for 문은 매우 유연해서, 어떤 요소를 넣느냐에 따라 세 가지 형태의 다른 반복문처럼 동작할 수 있어요. 무작정 코드를 타이핑하기보다는 어떤 상황에 어떤 구조를 쓸 것인지 결정하는 기준을 세우는 것이 먼저예요.
반복문 선택을 위한 상황별 가이드
상황에 따라 가장 적합한 반복 방식이 달라져요. 아래 표를 통해 어떤 경우에 어떤 형식을 선택해야 하는지 미리 확인해 보세요.
| 반복 방식 | 주요 용도 | 장점 |
|---|---|---|
| 표준 for 문 | 횟수가 정해진 카운팅 | 인덱스 제어가 매우 정밀함 |
| 조건식 for 문 | 특정 조건이 만족될 때까지 | while 문과 동일한 직관성 |
| range for 문 | 컬렉션(Slice, Map 등) 순회 | 가독성이 높고 인덱스 실수를 방지함 |
| 무한 for 문 | 서버 대기, 지속적 작업 | 명확한 제어 흐름 설계 가능 |
반복문 작성 전 체크리스트
코드를 쓰기 전, 스스로에게 다음 질문을 던져보세요. 이 질문들에 대한 답이 명확할수록 버그 없는 깔끔한 코드가 탄생해요.
- 종료 조건이 명확한가요? 종료 조건이 불분명하면 프로그램이 영원히 멈추지 않는 무한 루프의 함정에 빠져요.
- 인덱스 범위를 벗어나지는 않나요? 슬라이스의 길이를 넘어서는 인덱스에 접근하면 프로그램이 즉시 패닉(Panic) 상태에 빠져요.
- 불필요한 변수를 생성하고 있지는 않나요? Go는 변수 선언에 엄격해요. 사용하지 않는 인덱스 변수가 있다면 반드시 빈 식별자(_)를 사용해야 해요.
Go의 반복문은 다른 언어의 while 문을 포함하는 더 넓은 개념이에요. 즉, Go의 for 문을 제대로 배우면 다른 언어의 다양한 반복문을 모두 이해한 것과 다름없어요.
실전에서 바로 쓰는 Go 반복문 패턴
이제 본격적으로 Go의 반복문을 단계별로 살펴볼게요. 단순한 문법 설명을 넘어, 실제 개발 환경에서 어떤 식으로 코드가 구성되는지 구체적인 예시와 함께 확인해 보세요.
STEP 1. 정밀한 제어가 가능한 표준 for 문
가장 기본이 되는 형태로, 숫자를 하나씩 증가시키거나 감소시키며 정해진 횟수만큼 반복할 때 사용해요. 초기화, 조건식, 증감식의 세 가지 요소를 한 줄에 작성하는 것이 특징이에요.
// 0부터 9까지 10번 반복하는 가장 기본적인 형태예요
for i := 0; i < 10; i++ {
fmt.Println(i)
}
이 방식은 인덱스 값을 직접 조작해야 할 때 매우 유용해요. 예를 들어, 한 번에 2씩 건너뛰거나, 숫자를 역순으로 세어야 하는 경우에는 이 표준 for 문이 가장 강력한 도구가 돼요. 만약 조건식만 남기고 초기화나 증감식을 생략하면, 그 자체로 무한 루프가 된다는 점도 기억해 두세요.
STEP 2. 조건을 기반으로 동작하는 while 스타일
Go에는 별도의 while 키워드가 없어요. 하지만 for 문에서 조건식만 남겨두면 우리가 흔히 아는 while 문과 똑같이 동작하게 돼요. 특정 상태가 유지되는 동안 계속해서 작업을 수행해야 할 때 사용해요.
count := 1
// count가 5보다 작을 때까지만 계속 실행돼요
for count < 5 {
fmt.Println("현재 값:", count)
count++
}
이 패턴은 주로 데이터 스트림을 읽거나, 어떤 작업이 완료될 때까지 대기해야 하는 로직에서 자주 쓰여요. 조건을 어떻게 설정하느냐에 따라 루프의 생명 주기가 결정되므로, 조건식이 항상 변하는 변수를 포함하고 있는지 반드시 확인해야 해요.
STEP 3. 컬렉션을 순회하는 range 문법
Go 개발자들이 가장 많이, 그리고 가장 선호하는 방식이에요. 슬라이스(Slice), 배열(Array), 맵(Map), 문자열(String) 같은 데이터 집합을 하나씩 꺼내올 때 사용해요. 인덱스와 실제 값을 동시에 얻을 수 있어 매우 편리해요.
fruits := []string{"사과", "바나나", "포도"}
// index와 value를 모두 가져오는 방식이에요
for i, fruit := range fruits {
fmt.Printf("%d번째 과일: %s\n", i, fruit)
}
// 인덱스가 필요 없다면 빈 식별자(_)를 사용하세요
for _, fruit := range fruits {
fmt.Println("과일 이름:", fruit)
}
여기서 주의할 점은 맵(Map)을 순회할 때예요. 맵은 데이터가 들어있는 순서가 보장되지 않기 때문에, 실행할 때마다 순회 순서가 달라질 수 있어요. 만약 항상 일정한 순서로 데이터를 처리해야 한다면, 키(Key) 값들을 별도의 슬라이스에 담아 정렬한 뒤 그 슬라이스를 기반으로 순회하는 전략을 써야 해요.
STEP 4. 흐름을 제어하는 break와 continue
반복문 도중에 특정 상황이 발생했을 때 흐름을 끊거나 건너뛰어야 할 때가 있죠? 이때 사용하는 것이 바로 제어 키워드예요.
- break: 반복문을 즉시 종료하고 루프 밖으로 탈출해요.
- continue: 현재 진행 중인 단계만 건너뛰고 다음 반복으로 바로 넘어가요.
for i := 1; i <= 10; i++ {
if i%2 == 0 {
continue // 짝수일 때는 출력하지 않고 다음 숫자로 넘어가요
}
if i > 7 {
break // 7보다 커지면 반복을 완전히 멈춰요
}
fmt.Println("홀수 출력:", i)
}
STEP 5. 중첩 루프 탈출을 위한 라벨(Label) 사용법
반복문 안에 또 다른 반복문이 있는 중첩 구조에서는 `break` 하나만으로는 가장 바깥쪽 루프까지 한 번에 나갈 수 없어요. 이때 사용하는 기술이 바로 라벨이에요.
OuterLoop: // 라벨을 정의해요
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
fmt.Println("중첩 루프 탈출!")
break OuterLoop // OuterLoop라는 이름의 루프를 통째로 빠져나가요
}
fmt.Printf("i: %d, j: %d\n", i, j)
}
}
라벨은 복잡한 알고리즘을 구현할 때 매우 강력한 도구가 되지만, 너무 남발하면 코드의 가독성을 해칠 수 있으니 꼭 필요한 상황에서만 사용하는 것을 권장해요.
무한 루프를 방지하기 위해, `for { ... }` 구조를 사용할 때는 반드시 내부 로직 어딘가에 `break` 조건이나 함수를 종료하는 `return`이 포함되어 있는지 검토해야 해요.
자주 하는 실수와 해결법 및 FAQ
반복문을 작성하다 보면 누구나 한 번쯤 실수를 하게 마련이에요. 특히 Go 언어 특유의 동작 방식 때문에 발생하는 실수는 숙련된 개발자들도 가끔 놓치곤 하죠. 흔히 발생하는 실수들을 정리해 두었으니 꼭 확인해 보세요.
자주 하는 실수와 해결법
- ❌ 고루틴 안에서 반복문 변수를 그대로 사용하기
반복문이 돌아가는 도중에 고루틴을 생성하면, 모든 고루틴이 마지막 인덱스 값만 참조하게 될 수 있어요.
✅ 해결법: 고루틴을 호출할 때 매개변수로 현재의 변수 값을 직접 전달하여 값을 복사(Copy)해서 넘겨주어야 해요. - ❌ 사용하지 않는 range 인덱스 변수 방치하기
Go는 선언된 변수를 사용하지 않으면 컴파일 에러를 발생시켜요.
✅ 해결법: 인덱스나 값이 필요 없다면 반드시 `_` (빈 식별자)를 사용하여 명시적으로 무시하세요. - ❌ 반복 중 슬라이스 크기 변경하기
반복문이 돌아가는 도중에 슬라이스의 요소를 삭제하거나 추가하면 인덱스가 꼬여 엉뚱한 데이터를 참조할 수 있어요.
✅ 해결법: 요소를 삭제할 때는 뒤에서부터 거꾸로 순회하거나, 새로운 슬라이스에 결과값을 담는 방식을 사용하세요. - ❌ 무한 루프를 유발하는 조건식 설정
조건식이 항상 `true`가 되도록 설계하면 프로그램이 응답하지 않아요.
✅ 해결법: 루프 내부에서 조건 변수가 확실하게 변화하는지, 혹은 탈출 조건이 도달 가능한지 시뮬레이션해 보세요. - ❌ 맵(Map) 순회 순서에 의존하는 로직 작성
맵은 순서가 매번 바뀌기 때문에 결과가 매번 달라질 수 있어요.
✅ 해결법: 결과의 일관성이 중요하다면 키 값을 정렬한 뒤 슬라이스를 통해 순회하세요.
자주 묻는 질문
Q. Go에는 while 문이 없나요?
없어요. 대신 `for` 키워드 하나로 조건문만 남겨서 `while`처럼 사용할 수 있답니다.
Q. range 문에서 인덱스만 가져오고 싶은데 어떻게 하나요?
`for i := range slice`와 같이 작성하면 값 없이 인덱스만 깔끔하게 가져올 수 있어요.
Q. 중첩 루프에서 안쪽 루프만 빠져나가고 싶어요.
그냥 `break`를 사용하면 현재 속해 있는 가장 가까운 루프 하나만 탈출해요.
Q. for 문 안에서 변수를 새로 선언하면 어떻게 되나요?
`i := 0` 처럼 선언하면 해당 루프 블록 안에서만 유효한 새로운 변수가 만들어져요. 외부 변수와 이름이 같아도 섀도잉(Shadowing) 현상이 발생할 수 있으니 주의해야 해요.
Q. 무한 루프를 안전하게 만드는 방법이 있나요?
`for { ... }` 구조를 쓰되, 반드시 내부에 특정 조건이 맞으면 `return`이나 `break`가 실행되도록 설계하는 습관을 가져야 해요.
반복문 마스터를 위한 최종 요약
오늘 우리는 Go 언어의 핵심인 `for` 반복문에 대해 깊이 있게 다뤄보았어요. Go의 반복문은 단순해 보이지만, 그 안에 담긴 활용도는 무궁무진하답니다. 마지막으로 오늘 배운 내용을 머릿속에 저장해 두세요.
- Go는 오직
for키워드 하나로 모든 반복을 수행해요. - 정밀한 제어가 필요할 땐 표준 for 문을 사용하세요.
- 컬렉션 순회에는 가독성이 좋은 range 문이 정답이에요.
- 사용하지 않는 변수는 반드시 _ (빈 식별자)로 처리해야 해요.
- 중첩 루프 탈출이 필요할 땐 라벨(Label)을 활용하세요.
- 고루틴 사용 시 반복문 변수 복사 문제를 항상 경계하세요.
이제 이론은 충분해요. 직접 코드를 작성하며 손에 익히는 과정이 반드시 필요해요. 지금 바로 에디터를 열고, 방금 배운 `range` 문법을 활용해 간단한 숫자의 합을 구하는 프로그램을 만들어 보는 건 어떨까요?
실습을 진행하다가 막히는 부분이나 궁금한 점이 생기면 주저하지 말고 댓글로 남겨 주세요. 여러분의 성장을 진심으로 응원하며, 정성껏 답변해 드릴게요!
함께 읽으면 좋은 글: Go 반복문 완전 정복 가이드