[IT-정보] Go 반복문 치트시트: 핵심을 한눈에 – 입문자를 위한 실전 문법과 패턴 정리

반복문 for 개념을 시각화한 Go 프로그래밍 일러스트

Go 반복문, 왜 이것만 알면 될까요?

다른 언어를 배우다 Go(Golang)로 넘어온 개발자들이 가장 먼저 당황하는 지점이 있어요. 바로 while 문이 없다는 사실이에요. 파이썬이나 자바를 쓰던 분들은 조건문만 있는 루프를 찾으려 애쓰지만, Go는 오직 for 하나로 모든 반복을 해결해요.

이 구조는 처음에는 낯설지만, 익숙해지면 코드의 복잡성을 줄이는 데 큰 도움이 돼요. 반복문 하나가 세 가지 역할을 동시에 수행하기 때문이에요. 하지만 이 강력한 도구를 제대로 다루지 못하면 무한 루프에 빠지거나, 슬라이스의 범위를 벗어나 프로그램이 갑자기 멈춰버리는 사고를 겪기 쉬워요.

단순히 문법을 외우는 것보다 어떤 상황에서 어떤 형태의 for를 꺼내 써야 하는지 아는 것이 훨씬 중요해요. 이 글은 입문자가 실무에서 마주할 수 있는 구체적인 상황을 중심으로 Go 반복문의 모든 것을 정리했어요.

💡 이 글에서 다루는 내용

  • Go 반복문의 세 가지 기본 형태와 문법 구조
  • 슬라이스와 맵을 효율적으로 순회하는 range 활용법
  • 실무에서 바로 쓰는 반복문 제어와 최적화 패턴
  • 초보자가 가장 자주 저지르는 치명적인 실수 5가지

반복문 사용 전 꼭 알아야 할 기초 지식

Go의 반복문을 본격적으로 다루기 전에, 우리가 사용할 도구의 성격을 명확히 이해해야 해요. Go는 언어의 단순함을 지향하기 때문에, 다른 언어에 산재한 여러 반복 구문을 for라는 하나의 키워드로 통합했어요. 따라서 우리가 배우는 것은 ‘for의 변주곡’이라고 이해하면 쉬워요.

반복문을 작성할 때는 단순히 숫자를 올리는 것 이상으로, 종료 조건이 명확한지를 항상 먼저 생각해야 해요. 조건이 모호하면 프로그램은 멈추지 않고 CPU 자원을 무한히 잡아먹는 무한 루프 상태에 빠지게 돼요. 또한, 순회하려는 대상이 슬라이스인지, 맵인지, 아니면 단순한 숫자 범위인지에 따라 선택해야 할 문법이 완전히 달라져요.

반복 형태별 특징 비교

상황에 맞는 최적의 반복 방식을 선택할 수 있도록 아래 표를 참고해 보세요.

반복 유형 주요 용도 핵심 특징
기본형 (C-style) 특정 횟수 반복, 인덱스 제어 초기값, 조건식, 증감식을 직접 관리해요.
조건식 형태 특정 조건이 만족될 때까지 반복 기존의 while 문과 동일하게 동작해요.
range 형태 슬라이스, 배열, 맵 순회 인덱스와 값을 자동으로 추출해줘서 안전해요.
무한 루프 지속적인 작업 수행 (서버 등) 조건 없이 실행하며 break로 탈출해야 해요.

위 표를 보면 알 수 있듯이, Go의 반복문은 매우 유연해요. 하지만 유연하다는 것은 그만큼 개발자가 책임져야 할 부분이 많다는 뜻이기도 하죠. 이제 본격적으로 각 문법이 어떻게 작성되는지 실전 예제를 통해 살펴볼게요.

실전 Go 반복문 문법과 활용 패턴

이제 본격적으로 Go 반복문 치트시트의 핵심인 문법 패턴을 하나씩 파헤쳐 볼게요. 각 단계는 기초부터 심화 패턴까지 단계별로 구성되어 있어요.

STEP 1. 전통적인 C 스타일의 for 문법

가장 기본적인 형태예요. 반복 횟수를 정확히 제어하거나, 인덱스를 특정한 간격(예: 2씩 증가)으로 움직여야 할 때 사용해요. 구조는 초기화; 조건식; 증감식 순서로 이루어져요.

💡 코드 예시
for i := 0; i < 5; i++ {
  fmt.Println("현재 숫자:", i)
}

여기서 주의할 점은 조건식이 false가 되는 순간 즉시 루프를 빠져나온다는 점이에요. 인덱스 변수 i의 생명 주기는 for 루프 블록 안에서만 유효하므로, 루프 외부에서 i를 사용하려고 하면 에러가 발생하니 주의하세요.

STEP 2. range를 이용한 안전한 데이터 순회

슬라이스나 배열, 맵(Map)을 다룰 때는 이 방식이 가장 권장돼요. 인덱스를 직접 계산하다가 발생할 수 있는 Index Out of Range 에러를 원천 차단할 수 있기 때문이에요.

슬라이스를 순회할 때는 인덱스와 값을 동시에 받을 수 있어요. 만약 값만 필요하다면 인덱스 자리에 언더바(_)를 사용하여 무시할 수 있어요.

💡 코드 예시
nums := []int{10, 20, 30}
for i, v := range nums {
  fmt.Printf("인덱스: %d, 값: %d\n", i, v)
}

맵을 순회할 때는 key, value := range myMap 형태로 사용해요. 한 가지 꼭 기억해야 할 특징은 맵의 순회 순서는 실행할 때마다 달라질 수 있다는 점이에요. 순서가 중요한 로직이라면 반드시 키를 정렬한 뒤에 순회해야 해요.

STEP 3. 조건문만 사용하는 while 스타일

Go에는 별도의 while 키워드가 없지만, for 문에서 초기화와 증감식을 생략하면 완벽하게 while 문처럼 동작해요. 특정 상태가 유지되는 동안 계속 작업을 수행해야 하는 서버 로직이나 데이터 스트림 처리에서 자주 쓰여요.

💡 코드 예시
count := 1
for count < 5 {
  fmt.Println("카운트:", count)
  count++
}

이 방식은 조건이 참인 동안 무한히 실행될 위험이 있으므로, 루프 내부에서 반드시 조건을 변화시키는 코드가 포함되어 있는지 확인해야 해요.

STEP 4. 루프 제어: break와 continue

반복문의 흐름을 세밀하게 조절하려면 제어문을 적절히 섞어 써야 해요. break는 루프를 즉시 종료하고, continue는 현재 차례의 남은 코드를 건너뛰고 다음 반복으로 넘어가게 해줘요.

특히 다중 루프(중첩 루프)를 사용할 때는 break 하나만으로는 가장 안쪽의 루프만 빠져나간다는 사실을 잊지 마세요. 전체 루프를 한 번에 탈출하고 싶다면 라벨(Label) 기능을 활용해야 해요.

STEP 5. 실전 시나리오: 데이터 필터링 예제

실무에서는 단순히 숫자를 세는 것보다, 데이터 집합에서 특정 조건에 맞는 항목만 골라내는 작업이 훨씬 많아요. 아래는 사용자 리스트에서 활성 상태인 사용자만 추출하는 시나리오예요.

💡 실전 시나리오 코드
type User struct {
  Name string
  Active bool
}

users := []User{
  {"Kim", true},
  {"Lee", false},
  {"Park", true},
}

activeUsers := []string{}
for _, u := range users {
  if u.Active {
    activeUsers = append(activeUsers, u.Name)
  }
}

이처럼 range로 데이터를 순회하면서 if 조건문과 append 함수를 조합하는 패턴은 Go 개발자가 매일 마주하는 가장 기본적인 패턴 중 하나예요. 이 패턴만 능숙하게 다뤄도 기초적인 데이터 처리는 충분히 가능해요.

자주 하는 실수와 해결법 및 FAQ

반복문을 작성하다 보면 이론과 실제 구현 사이에서 괴리가 생기곤 해요. 많은 입문자가 공통적으로 겪는 문제들을 정리했어요.

자주 하는 실수와 해결법

실수: 슬라이스 인덱스 범위 초과
for i := 0; i <= len(slice); i++와 같이 등호(=)를 잘못 붙여 루프를 돌리는 경우예요. 이 경우 슬라이스의 마지막 인덱스를 넘어선 지점에서 프로그램이 panic을 일으키며 멈춰버려요.
해결법: 항상 조건을 i < len(slice)로 설정하여 마지막 인덱스까지만 접근하도록 주의하세요.

실수: range 루프 내 변수 주소 참조 문제
Go의 range는 루프를 돌 때 매번 새로운 변수를 만드는 게 아니라, 동일한 변수의 값만 업데이트해요. 그래서 루프 안에서 해당 변수의 포인터(주소)를 슬라이스에 담으면 모든 요소가 마지막 값만 가리키게 되는 대참사가 발생해요.
해결법: 루프 내부에서 변수를 새로 할당하거나, 값 자체를 복사해서 사용하세요.

실수: 무한 루프에 의한 리소스 고갈
조건이 항상 참이 되거나, break 문을 빠뜨려 프로그램이 종료되지 않는 경우예요.
해결법: 루프 설계 단계에서 반드시 탈출 조건을 명시하고, 디버깅 시 루프 내부의 상태 변화를 로그로 확인하세요.

실수: 맵 순회 순서에 의존하는 로직
맵은 순서가 보장되지 않는데, 마치 순서가 있는 것처럼 코드를 짜는 경우예요.
해결법: 순서가 중요하다면 맵의 키들을 별도의 슬라이스에 담아 정렬한 후, 그 슬라이스를 기반으로 반복문을 돌리세요.

실수: 불필요한 연산을 루프 안에 배치
반복 횟수가 많을 때, 변하지 않는 계산식을 루프 안에 넣으면 성능이 급격히 떨어져요.
해결법: 루프 외부에서 미리 계산할 수 있는 값은 반드시 밖으로 빼내세요.

자주 묻는 질문

Q. Go에는 while 문이 정말 하나도 없나요?
네, 맞아요. 하지만 for 문을 활용하면 모든 while 문의 기능을 완벽하게 대체할 수 있어요. 문법이 하나인 덕분에 코드가 더 간결해지는 장점이 있죠.

Q. range를 쓸 때 인덱스가 필요 없으면 어떻게 하나요?
인덱스 자리에 언더바(_)를 넣으면 돼요. 예: for _, value := range slice. 이렇게 하면 컴파일러가 "사용하지 않는 변수"라며 에러를 내는 것을 방지할 수 있어요.

Q. 중첩 루프에서 한 번에 전체를 빠져나가고 싶어요.
라벨을 사용하세요. OuterLoop: for ... { for ... { break OuterLoop } }와 같이 작성하면 가장 바깥쪽 루프까지 즉시 탈출할 수 있어요.

Q. for 문 안에서 함수를 호출하면 성능에 영향이 큰가요?
함수 호출 자체가 비용을 발생시키긴 하지만, 현대의 컴파일러는 매우 똑똑해요. 다만, 루프 내에서 매번 무거운 연산이나 네트워크 요청을 하는 것은 반드시 피해야 해요.

Q. for i := range slice 형식을 써도 되나요?
네, 가능해요! 이 방식은 값(value)은 필요 없고 인덱스(index)만 필요할 때 아주 유용하고 깔끔한 방법이에요.

성공적인 Go 개발을 위한 마무리

지금까지 Go의 유일한 반복문인 for의 모든 형태와 실전 활용법을 살펴보았어요. 처음에는 문법이 단조로워 보여서 당황스러울 수 있지만, 이 단순함 속에 숨겨진 강력한 제어력을 이해한다면 여러분의 Go 코드는 훨씬 더 견고하고 효율적으로 변할 거예요.

✅ 핵심 요약

  • Go는 for 하나로 기본, 조건, 무한 루프를 모두 처리해요.
  • 슬라이스나 맵 순회 시에는 안전한 range 사용을 우선하세요.
  • 맵 순회는 순서가 매번 바뀐다는 점을 절대 잊지 마세요.
  • range 사용 시 변수의 주소값을 직접 참조하지 않도록 주의하세요.
  • 복잡한 탈출이 필요할 땐 라벨(Label)을 활용해 보세요.
  • 루프 내부에는 반드시 탈출 조건이나 상태 변화가 있어야 해요.

이제 이론은 충분해요. 직접 에디터를 켜고 다양한 슬라이스와 맵을 만들어 반복문을 돌려보며 손에 익히는 과정이 필요해요. 작은 실수 하나가 큰 버그를 만들 수 있다는 점을 기억하며, 코드를 작성할 때마다 조건을 다시 한번 검토하는 습관을 들여보세요.

오늘 바로 실천할 일:
1. 기존에 작성했던 반복문 코드를 range를 사용해 더 깔끔하게 리팩토링해 보세요.
2. 중첩 루프에서 라벨을 사용해 탈출하는 예제를 직접 작성해 보세요.

글을 읽으며 이해가 가지 않거나, 실제 구현 중에 막히는 부분이 있다면 언제든 댓글로 남겨 주세요. 여러분의 학습을 돕기 위해 정성껏 답변해 드릴게요!

함께 읽으면 좋은 글: Go 반복문 완전 정복 가이드

댓글 남기기