[IT-정보] Go 반복문 치트시트: 핵심 문법 정리 – 입문 개발자를 위한 실전 코드와 패턴 가이드

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

반복문 for 하나로 끝내는 Go 프로그래밍

파이썬이나 자바스크립트를 배우다가 Go 언어의 문법을 처음 마주하면 당황스러운 순간이 찾아와요. 분명히 무언가를 반복하고 싶은데, 문법 문서 어디를 뒤져봐도 while이라는 키워드가 보이지 않기 때문이에요. 코드를 짜다가 “어? while문은 어디 있지?”라며 당황하며 구글링을 시작했다면, 당신은 이미 많은 입문 개발자가 겪는 첫 번째 관문에 도착한 거예요.

Go 언어의 설계 철학은 단순함이에요. 복잡한 기능을 여러 개 만드는 대신, 가장 강력한 도구 하나를 제대로 만드는 방식을 택했어요. 그 결과, Go에는 오직 ‘for’라는 이름의 반복문 하나만 존재해요. 이 하나의 키워드가 기존 언어의 while문, do-while문, 그리고 전통적인 for문의 역할을 모두 수행하죠. 처음에는 이것이 불편하게 느껴질 수 있지만, 익숙해지면 오히려 코드의 구조가 훨씬 명확해지는 경험을 하게 될 거예요.

반복문을 제대로 다루지 못하면 데이터 배열을 처리하거나 서버에서 들어오는 요청을 지속적으로 감시하는 로직을 짤 때 심각한 오류를 범하기 쉬워요. 무한 루프에 빠져 CPU 점유율이 100%를 찍거나, 슬라이스의 인덱스 범위를 벗어나 프로그램이 갑자기 종료되는 상황은 초보 개발자에게 흔한 일이죠.

이 글에서는 Go 반복문 치트시트로서, 당신이 현업에서 즉시 사용할 수 있는 모든 반복 패턴을 정리해 드릴게요. 이 가이드를 끝까지 읽고 나면, 더 이상 Go에서 반복문을 어떻게 써야 할지 고민하며 시간을 허비하지 않게 될 거예요.

이 글에서 배우게 될 내용

  • 전통적인 3요소 방식의 for문 사용법
  • while문을 대체하는 조건부 for문 활용법
  • 슬라이스와 맵을 위한 range 문법 완벽 이해
  • 실무에서 바로 쓰는 유용한 반복 패턴과 제어문
  • 초보자가 가장 많이 틀리는 5가지 실수와 해결책

Go 반복문을 시작하기 전 꼭 알아야 할 기본 개념

Go의 반복문을 본격적으로 다루기 전에, 우리가 사용할 도구들의 특성을 먼저 이해해야 해요. Go는 다른 언어에 비해 문법적 자유도를 제한하는 대신, 코드를 읽는 사람이 의도를 명확히 파악할 수 있도록 유도해요. 반복문 역시 예외는 아니에요. 조건이 명확하지 않은 반복은 지양해야 하며, 모든 반복의 끝은 반드시 예측 가능해야 해요.

먼저 Go의 반복문이 처리하는 세 가지 핵심 요소를 머릿속에 그려보세요. 첫째는 시작 지점을 정하는 초기화 문구, 둘째는 반복을 계속할지 결정하는 조건식, 셋째는 한 번의 반복이 끝날 때마다 실행되는 증감식이에요. Go에서는 이 세 가지를 한 줄에 적을 수도 있고, 조건식만 남겨서 마치 while문처럼 쓸 수도 있어요.

💡 알아두기
Go에서 반복문을 사용할 때 가장 중요한 것은 ‘종료 조건’이에요. Go는 다른 언어처럼 루프 내부에서 복잡한 상태 변화를 허용하기보다, 반복문 선언부에서 흐름을 제어하는 것을 선호해요.

반복문을 선택할 때 어떤 형식을 써야 할지 고민된다면 아래 비교 표를 참고해 보세요. 상황에 맞는 최적의 도구를 선택하는 것이 효율적인 코딩의 첫걸음이에요.

반복 유형 사용 문법 (Syntax) 가장 적합한 상황
표준형 for for i := 0; i < n; i++ 횟수가 정해진 숫자 반복
조건형 for for condition { … } 특정 조건이 충족될 때까지 반복 (while 대체)
범위형 range for k, v := range collection 슬라이스, 배열, 맵의 요소를 순회할 때
무한 루프 for { … } 서버 대기, 이벤트 루프 등 종료 시점이 불분명할 때

이 표를 통해 알 수 있듯이, Go에서는 상황에 따라 for문의 형태를 변형하여 사용해요. 무조건 하나의 방식만 고집하기보다는, 지금 내가 다루려는 데이터가 무엇인지, 언제 멈춰야 하는지를 먼저 생각하는 습관을 들여야 해요.

실전 Go 반복문 패턴 5단계 가이드

이제 본격적으로 실무에서 사용되는 Go 반복문 for 예제를 살펴볼게요. 각 단계별로 문법의 구조와 함께 어떤 상황에서 이 패턴을 사용하는지 자세히 설명해 드릴게요.

STEP 1. 가장 기본적인 표준형 for문 활용하기

가장 먼저 익혀야 할 패턴은 우리가 흔히 아는 C 스타일의 반복문이에요. 숫자를 세거나, 특정 횟수만큼 코드를 반복해야 할 때 사용해요. 세 가지 구성 요소인 초기화, 조건식, 후속 처리가 한 줄에 들어가는 것이 특징이에요.

// 1부터 5까지 출력하는 표준형 for문
for i := 1; i <= 5; i++ {
    fmt.Println("숫자:", i)
}

여기서 i := 1은 반복이 시작될 때 딱 한 번 실행되는 초기화 식이에요. i <= 5는 매 반복마다 체크하는 조건식이고, i++는 한 번의 반복이 끝날 때마다 실행되는 증감식이죠. 이 구조는 루프의 시작과 끝이 명확하기 때문에 가장 안전하고 예측 가능한 반복 방식이에요.

STEP 2. While문을 대체하는 조건부 for문

Go에는 while문이 없지만 걱정 마세요. 조건식만 남겨두면 바로 while문이 된답니다. 특정 변수의 상태가 변할 때까지, 혹은 어떤 값이 올 때까지 계속 실행해야 하는 로직에 아주 유용해요.

// count가 10이 될 때까지 반복하는 조건부 for문
count := 0
for count < 10 {
    count += 2
    fmt.Println("현재 카운트:", count)
}

이 방식은 반복 횟수가 미리 정해져 있지 않을 때 최고의 효율을 보여줘요. 예를 들어, 네트워크에서 데이터를 읽어오다가 데이터가 더 이상 없을 때까지 반복하거나, 사용자가 특정 키를 누를 때까지 프로그램을 실행하는 상황에서 이 패턴을 사용해요. 이때 주의할 점은 조건식이 반드시 거짓이 되는 순간이 존재하도록 루프 내부 로직을 짜야 한다는 점이에요. 그렇지 않으면 프로그램이 무한히 돌아가는 대참사가 발생할 수 있어요.

STEP 3. 무한 루프와 탈출 전략 (break, continue)

때로는 조건 없이 계속 돌아가는 루프가 필요할 때가 있어요. 서버가 24시간 내내 요청을 기다리는 것처럼 말이죠. 이때는 조건식을 비워둔 채 for {} 형태를 사용해요. 하지만 무한 루프를 제어하려면 반드시 탈출 조건을 함께 설계해야 해요.

// 무한 루프와 제어문 예제
for {
    input := getNextInput() // 입력을 받는다고 가정
    
    if input == "exit" {
        fmt.Println("프로그램을 종료합니다.")
        break // 루프를 즉시 빠져나감
    }
    
    if input == "skip" {
        continue // 이번 회차만 건너뛰고 다음 반복으로 이동
    }
    
    fmt.Println("입력값:", input)
}

여기서 break는 루프 전체를 즉시 종료하고 다음 코드로 넘어가게 해줘요. 반면 continue는 현재 진행 중인 루프의 나머지 부분을 무시하고 바로 다음 증감식이나 조건 검사 단계로 점프하게 만들죠. 이 두 가지 키워드만 잘 써도 루프의 흐름을 아주 유연하게 조절할 수 있어요.

STEP 4. 데이터를 훑는 마법, for range문

실무 개발자의 시간 80%는 데이터를 순회(Iteration)하는 데 쓰인다고 해도 과언이 아니에요. Go에서는 슬라이스(Slice), 배열(Array), 맵(Map), 채널(Channel)을 아주 쉽게 훑을 수 있도록 range 키워드를 제공해요. 인덱스와 값을 동시에 가져올 수 있어 매우 강력하죠.

// 슬라이스 순회 예제
fruits := []string{"사과", "바나나", "포도"}
for index, value := range fruits {
    fmt.Printf("%d번째 과일은 %s입니다.\n", index, value)
}

// 맵(Map) 순회 예제
scores := map[string]int{"철수": 90, "영희": 85}
for name, score := range scores {
    fmt.Printf("%s의 점수: %d\n", name, score)
}

슬라이스에서는 인덱스와 값을 반환하지만, 맵(Map)을 순회할 때는 키와 값을 반환해요. 여기서 아주 중요한 팁 하나를 드릴게요. 맵의 순회 순서는 매번 달라질 수 있어요. Go의 맵은 내부적으로 순서가 보장되지 않기 때문에, 똑같은 코드를 실행해도 매번 출력되는 순서가 다를 수 있다는 점을 반드시 기억해야 해요. 만약 순서가 중요하다면 별도의 슬라이스에 키를 담아 정렬한 뒤 순회해야 해요.

STEP 5. 고급 패턴: 레이블(Label)과 중첩 루프 제어

루프 안에 루프가 있는 중첩 루프 상황에서, 안쪽 루프를 탈출할 때 바깥쪽 루프까지 한꺼번에 종료하고 싶다면 어떻게 해야 할까요? 단순히 break를 쓰면 가장 가까운 루프만 빠져나가게 되죠. 이때 사용하는 것이 바로 레이블(Label)이에요.

// 레이블을 이용한 중첩 루프 탈출
OuterLoop:
for i := 1; i <= 3; i++ {
    for j := 1; j <= 3; j++ {
        if i == 2 && j == 2 {
            fmt.Println("조건 충족! 모든 루프를 종료합니다.")
            break OuterLoop // OuterLoop라는 이름의 루프를 탈출
        }
        fmt.Printf("i:%d, j:%d\n", i, j)
    }
}

이 방식은 코드가 조금 복잡해 보일 수 있지만, 다중 루프를 제어해야 하는 복잡한 알고리즘이나 데이터 처리 로직에서 매우 유용하게 쓰여요. 레이블을 명확하게 지정하면 코드를 읽는 동료 개발자도 "아, 이 break는 저 바깥쪽 루프를 깨는 거구나"라고 즉시 이해할 수 있어요.

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

Go의 반복문을 사용하다 보면 논리적으로는 맞는데 결과가 이상하거나, 프로그램이 멈추는 현상을 겪게 돼요. 개발자라면 누구나 한 번쯤 겪는 시행착오를 정리해 드릴게요.

자주 하는 실수와 해결법

실수: 루프 변수의 주소값 문제
for range를 사용할 때, 루프 변수(v)의 주소를 슬라이스에 저장하면 모든 요소가 마지막 요소의 값으로 채워지는 현상이 발생해요.
왜 발생하는가: Go의 range는 반복할 때마다 변수를 새로 만드는 것이 아니라, 기존 변수의 값을 업데이트하기 때문이에요.
해결법: 루프 내부에서 새로운 변수를 선언하여 값을 복사해 사용하세요. temp := v 형식을 활용하는 것이 좋아요.

실수: 슬라이스 순회 중 요소 삭제
for range로 슬라이스를 훑는 도중에 append나 삭제 작업을 하면 인덱스가 꼬여서 데이터를 건너뛰게 돼요.
왜 발생하는가: 슬라이스의 길이가 변하면서 인덱스 위치가 밀려나기 때문이에요.
해결법: 역순으로 반복문을 돌리거나(뒤에서부터 앞으로), 삭제할 인덱스를 따로 모아두었다가 루프가 끝난 뒤 처리하세요.

실수: 무한 루프에서의 탈출 조건 누락
for 조건식만 있고 내부에서 조건이 변하지 않는 경우 프로그램이 멈추지 않아요.
왜 발생하는가: 루프를 종료시킬 명확한 break나 조건 변화 로직이 없기 때문이에요.
해결법: 루프를 설계할 때 반드시 종료 시나리오를 먼저 정의하고 코드를 작성하세요.

실수: 맵(Map) 순서에 의존하는 로직
맵을 돌릴 때 항상 A, B, C 순서로 나올 것이라 가정하고 테스트 코드를 짜는 경우예요.
왜 발생하는가: Go의 맵은 무작위 순서를 보장하기 때문이에요.
해결법: 순서가 중요하다면 키(Key)들을 슬라이스에 담아 정렬한 뒤, 그 슬라이스를 바탕으로 맵에 접근하세요.

실수: 인덱스 범위 초과 (Off-by-one error)
i <= len(slice)와 같이 작성하여 에러를 발생시키는 경우예요.
왜 발생하는가: 슬라이스의 인덱스는 0부터 시작하여 length-1까지이기 때문이에요.
해결법: 항상 i < len(slice) 형태의 미만 연산자를 사용하세요.

자주 묻는 질문

Q. for range를 쓸 때 인덱스가 필요 없으면 어떻게 하나요?

인덱스를 무시하고 싶다면 언더스코어(_)를 사용하세요. for _, value := range slice처럼 작성하면 인덱스 변수를 선언하지 않고 값만 깔끔하게 가져올 수 있어요.

Q. while문이 정말 하나도 없나요?

네, 맞아요. 하지만 for condition { ... } 패턴이 while문의 역할을 완벽하게 수행하기 때문에 따로 만들 필요가 없는 것이랍니다.

Q. 성능 면에서 for와 range 중 무엇이 더 빠른가요?
대부분의 일반적인 상황에서는 차이가 거의 없어요. 다만, 아주 거대한 슬라이스를 다룰 때는 인덱스로 접근하는 전통적인 for문이 아주 미세하게 더 빠를 수 있지만, 가독성을 생각한다면 range를 권장해요.

Q. 무한 루프를 안전하게 멈추는 방법이 있나요?
프로그램 내부 로직으로는 break를 써야 하고, 만약 외부에서 강제로 멈춰야 한다면 OS의 시그널(Signal) 처리를 통해 종료 로직을 구현해야 해요.

반복문 마스터를 위한 마지막 체크리스트

오늘 배운 내용을 바탕으로 Go의 반복문을 완벽하게 내 것으로 만들 준비가 되셨나요? 복잡한 로직을 짤 때마다 이 가이드를 다시 꺼내 보셔도 좋아요. 반복문은 단순해 보이지만, 어떻게 쓰느냐에 따라 코드의 성능과 가독성이 극명하게 갈리는 아주 중요한 도구니까요.

✅ 핵심 요약

  • Go에는 'for' 하나로 모든 반복을 해결한다.
  • while문이 필요하면 'for condition' 패턴을 쓴다.
  • 데이터 순회는 'for range'가 가장 간결하고 안전하다.
  • 무한 루프를 제어할 때는 'break'와 'continue'를 적절히 섞는다.
  • 맵(Map) 순회는 매번 순서가 달라질 수 있음을 명심한다.
  • 중첩 루프를 한 번에 깨려면 '레이블(Label)'을 활용한다.

이제 이론은 충분해요. 다음 단계로 넘어가 볼까요? 지금 당장 빈 IDE를 열고 아래 작업들을 직접 해보세요.

  • 오늘 할 일: 1부터 100까지의 합을 구하는 for문 직접 짜보기
  • 이번 주 할 일: 슬라이스에 담긴 이름들을 range로 하나씩 출력하는 프로그램 만들기
  • 실행 직전 할 일: 맵(Map)을 사용하여 이름과 점수를 저장하고 무작위로 출력되는 것 확인하기

Go 언어의 매력은 단순함에서 오는 강력함에 있어요. 반복문도 마찬가지죠. 처음에는 어색하겠지만, 이 단순한 규칙들에 익숙해지면 어느샌가 군더더기 없는 깔끔한 Go 코드를 작성하는 자신을 발견하게 될 거예요. 공부하다가 막히는 부분이나 이해가 안 되는 예제가 있다면 언제든 댓글로 남겨 주세요. 여러분의 성장을 진심으로 응원할게요!

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

댓글 남기기