[IT-정보] Go 반복문 완벽 가이드 – 입문자를 위한 핵심 개념과 실전 예제

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

Go 프로그래밍의 심장, 반복문 for가 왜 중요한가요

수만 개의 사용자 데이터를 하나씩 확인하며 특정 조건을 만족하는 사람을 찾아야 하는 상황을 상상해 보세요. 일일이 손으로 확인하는 것은 불가능에 가깝고, 코드에서도 이를 하나하나 수동으로 적는 것은 매우 비효율적이에요. 이때 우리에게 필요한 것이 바로 반복문이에요. 반복문은 특정 조건이 충족될 때까지 동일한 명령을 자동으로 수행하게 만들어 주는 마법 같은 도구예요.

많은 개발 언어들이 while이나 do-while 같은 다양한 종류의 반복문을 제공하지만, Go 언어는 오직 for 하나만을 사용해요. 처음에는 이것이 제약처럼 느껴질 수 있지만, 사실은 언어의 단순함과 명확성을 극대화하기 위한 Go만의 철학이 담겨 있어요. 하나의 도구로 모든 상황을 해결할 수 있다면, 코드는 훨씬 간결해지고 읽기 쉬워지거든요. 하지만 이 ‘하나의 도구’를 제대로 다루지 못하면 무한 루프에 빠져 서버를 멈추게 하거나, 잘못된 메모리 참조로 프로그램을 종료시키는 실수를 저지르기 쉬워요.

지금 이 글을 읽고 계신 분들은 아마 Go를 막 배우기 시작했거나, 다른 언어에서 Go로 넘어오며 반복문의 독특한 구조에 당황하고 계실지도 몰라요. 반복문이 익숙하지 않으면 복잡한 비즈니스 로직을 구현할 때 코드의 흐름을 놓치기 쉽고, 이는 곧 버그로 이어져요. 그래서 Go 반복문 완벽 가이드를 통해 기초부터 탄탄하게 다지는 과정이 반드시 필요해요.

이 글을 끝까지 읽고 나면 여러분은 다음과 같은 능력을 갖추게 될 거예요.

  • Go의 유일한 반복문인 for의 다양한 활용 형태를 완벽히 이해해요.
  • 단순한 숫자 카운팅부터 복잡한 데이터 구조 순회까지 자유자재로 구현해요.
  • 실무에서 흔히 발생하는 반복문 관련 버그를 미리 방지하고 최적화할 수 있어요.

효율적인 루프 작성을 위한 사전 지식과 체크리스트

반복문을 본격적으로 작성하기 전에, Go 언어가 반복을 어떻게 처리하는지 그 구성 요소를 명확히 이해해야 해요. Go의 for 문은 크게 세 가지 구성 요소로 이루어져 있어요. 첫째는 초기화 문(init)으로 루프가 시작될 때 딱 한 번 실행되는 부분이에요. 둘째는 조건식(condition)으로, 이 식이 참(true)인 동안에만 루프가 계속 돌아가요. 셋째는 후처리 문(post)으로, 한 번의 반복이 끝날 때마다 실행되며 주로 변수의 값을 증가시키거나 감소시키는 역할을 해요.

이 구조를 이해하는 것이 중요한 이유는, Go가 다른 언어의 while 문을 별도로 두지 않고 이 세 요소를 조합해서 모든 형태의 반복을 구현하기 때문이에요. 따라서 각 요소가 언제, 어떻게 호출되는지 머릿속으로 그릴 수 있어야 코드의 흐름을 놓치지 않아요.

💡 알아두기
Go에서는 세미콜론(;)을 사용하여 초기화, 조건, 후처리 문을 구분해요. 만약 특정 요소가 필요 없다면 생략할 수도 있지만, 문법적 형식을 갖추는 것이 중요해요.

또한, 반복문을 사용할 때 어떤 방식을 선택할지 결정하기 위한 기준이 필요해요. 상황에 맞지 않는 반복 구조를 선택하면 코드가 읽기 어려워지고 성능이 저하될 수 있거든요. 아래 표를 통해 각 상황에 적합한 반복 패턴을 비교해 보세요.

반복 패턴 주요 특징 적합한 상황
표준형 for 초기화, 조건, 증감식 포함 정해진 횟수만큼 반복할 때
조건식 전용 조건식만 존재 (while 방식) 조건이 충족될 때까지 지속할 때
무한 루프 조건식 없이 실행 특정 신호를 기다릴 때
range 활용 컬렉션 요소를 직접 순회 배열, 슬라이스, 맵 순회 시

반복문을 작성하기 전, 스스로에게 질문해 보세요. “이 반복은 몇 번 실행되어야 하는가?” 혹은 “언제 멈춰야 하는가?” 이 질문에 대한 답이 명확해야 효율적인 반복문 설계가 가능해요. 준비가 되었다면 이제 실제 코드로 들어가 볼까요?

Go 반복문의 4가지 핵심 활용 패턴과 실전 예제

이제 본격적으로 Go의 반복문을 어떻게 사용하는지 단계별로 살펴볼게요. Go는 단 하나의 키워드만 사용하지만, 그 안에서 얼마나 다양한 변주가 가능한지가 핵심이에요. 반복문 for 예제를 통해 각 패턴의 동작 원리를 확실히 익혀보세요.

STEP 1. 가장 기본이 되는 표준형 for 루프

가장 먼저 익혀야 할 것은 우리가 흔히 알고 있는 전통적인 방식의 반복문이에요. 정해진 횟수만큼 숫자를 세거나, 인덱스를 기반으로 무언가를 실행할 때 가장 강력한 힘을 발휘해요.

예를 들어, 1부터 5까지 숫자를 출력하는 코드를 작성해 볼게요.
for i := 1; i <= 5; i++ { fmt.Println(i) }
이 코드에서 i := 1은 시작점을 알리고, i <= 5는 끝나는 지점을 결정하며, i++는 한 단계씩 나아가는 발걸음이 돼요. 이 구조를 정확히 이해하면, 어떤 복잡한 숫자 연산도 루프 안에서 자유롭게 제어할 수 있어요.

STEP 2. 조건식만 사용하는 while 스타일 루프

Go에는 `while`이라는 키워드가 따로 없어요. 하지만 실망할 필요는 없어요. 표준형 for 문에서 초기화 식과 후처리 식을 생략하면, 바로 while 문처럼 동작하기 때문이에요. 특정 조건이 참인 동안 계속해서 무언가를 수행해야 하는 상황에서 매우 유용해요.

예를 들어, 어떤 센서로부터 데이터가 들어올 때까지 계속 기다려야 하는 상황을 가정해 볼게요.
for sensor.IsActive() { // 데이터 처리 로직 }
이런 방식은 코드의 가독성을 높여줘요. 굳이 숫자를 세거나 인덱스를 조작할 필요 없이, 오로지 '상태'에만 집중할 수 있게 해주거든요. 조건이 거짓이 되는 순간 루프는 자연스럽게 종료돼요.

STEP 3. 무한 루프와 제어문(break, continue) 활용하기

때로는 조건 없이 무한히 돌아가는 루프가 필요할 때가 있어요. 서버가 계속 실행되면서 요청을 기다려야 하는 경우처럼 말이죠. Go에서는 조건식을 아예 비워둠으로써 무한 루프를 만들 수 있어요.
for { // 무한 반복 }

하지만 무한 루프는 매우 위험할 수 있어요. 반드시 탈출할 수 있는 통로를 만들어줘야 해요. 이때 사용하는 것이 breakcontinue예요.

  • break: 루프를 즉시 완전히 종료하고 탈출해요.
  • continue: 현재 차례의 실행을 건너뛰고 바로 다음 반복으로 넘어가요.

실제 시나리오를 들어볼까요? 1부터 100까지 숫자 중 짝수만 출력하다가, 숫자가 50이 되면 멈추고 싶다면 어떻게 할까요?
for i := 1; i <= 100; i++ { if i % 2 != 0 { continue } if i == 50 { break } fmt.Println(i) }
이처럼 제어문을 적절히 섞어 쓰면 매우 정교한 흐름을 제어할 수 있어요.

STEP 4. 컬렉션을 위한 강력한 도구, range 키워드

현대적인 프로그래밍에서 가장 많이 쓰이는 방식은 아마 배열이나 슬라이스, 맵(map) 같은 데이터 집합을 하나씩 꺼내보는 방식일 거예요. Go에서는 range 키워드를 사용하여 이 과정을 아주 우아하게 처리해요.

슬라이스를 순회할 때, range는 현재 요소의 인덱스(index)값(value)을 동시에 반환해 줘요.
for index, value := range mySlice { fmt.Printf("%d번째 값은 %v입니다\n", index, value) }
만약 인덱스가 필요 없다면 언더스코어(_)를 사용하여 무시할 수 있어요. 이는 Go의 강력한 특징 중 하나로, 사용하지 않는 변수를 허용하지 않는 언어의 규칙을 따르면서도 코드의 깔끔함을 유지해 준답니다.

💡 알아두기
맵(map)을 range로 순회할 때는 주의할 점이 있어요. 맵의 요소는 저장된 순서와 상관없이 무작위(random)로 추출돼요. 즉, 매번 실행할 때마다 결과의 순서가 달라질 수 있다는 점을 꼭 기억하세요!

마지막으로, 프로덕션 환경에서 고려해야 할 중첩 루프의 성능 문제에 대해서도 짚고 넘어가야 해요. 루프 안에 또 다른 루프가 있는 경우, 데이터의 양이 늘어남에 따라 실행 시간이 기하급수적으로 증가할 수 있어요. 예를 들어, 데이터가 1,000개일 때 중첩 루프는 1,000,000번의 연산을 수행하게 되죠. 따라서 복잡한 데이터를 다룰 때는 항상 시간 복잡도를 고민하는 습관을 들여야 해요.

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

반복문을 작성하다 보면 누구나 실수를 하기 마련이에요. 특히 숙련된 개발자조차 무심코 저지르는 실수들이 있죠. 아래의 사례들을 통해 자신의 코드를 점검해 보세요.

자주 하는 실수와 해결법

실수: 무한 루프에 빠져 프로그램이 멈춤
왜 발생하는가: 루프를 탈출할 조건(break)을 설정하지 않았거나, 조건식을 만족시키기 위한 변수(예: i++)를 업데이트하지 않았을 때 발생해요.
해결법: 루프를 설계할 때 반드시 '언제 이 루프가 끝나는가'를 먼저 정의하고, 조건식이 변함에 따라 반드시 탈출 조건에 도달하도록 로직을 확인하세요.

실수: range 사용 시 인덱스와 값의 혼동
왜 발생하는가: Go의 range는 (인덱스, 값) 순서로 반환하는데, 이를 (값, 인덱스)로 잘못 생각하여 엉뚱한 데이터를 출력할 때가 있어요.
해결법: 변수 이름을 idx, val처럼 명확하게 지어주는 습관을 들이세요. 이름만 잘 지어도 실수를 획기적으로 줄일 수 있어요.

실수: 루프 도중 슬라이스 크기 변경
왜 발생하는가: 반복문이 돌아가고 있는 도중에 슬라이스의 요소를 삭제하거나 추가하면, 인덱스가 꼬여서 예기치 못한 동작이나 패닉(panic)이 발생할 수 있어요.
해결법: 원본을 직접 수정하기보다는 새로운 슬라이스를 만들어 결과를 담거나, 뒤에서부터 거꾸로 순회하는 방식을 고려해 보세요.

실수: 맵(map) 순회 시 순서 의존성
왜 발생하는가: 맵은 순서가 보장되지 않는데, 마치 항상 같은 순서로 데이터가 나올 것이라고 가정하고 로직을 짜면 테스트 환경에서 버그가 터져요.
해결법: 순서가 중요하다면 맵의 키(key)를 슬라이스에 담아 정렬한 뒤, 그 슬라이스를 순회하며 맵의 값을 가져오는 방식을 사용하세요.

실수: 불필요하게 복잡한 중첩 루프
왜 발생하는가: 문제를 해결하기 위해 가장 먼저 떠오르는 것이 루프 안에 루프를 넣는 것이라, 성능 최적화를 간과하기 쉬워요.
해결법: 맵(map)이나 다른 자료구조를 활용해 중첩 루프를 단일 루프로 줄일 수 있는 방법이 없는지 항상 고민해 보세요.

자주 묻는 질문

Q. Go에는 왜 while 문이 따로 없나요?

Go의 철학은 '단순함'이에요. for 문 하나만으로 모든 반복을 구현할 수 있다면 언어의 문법이 간결해지고 학습 곡선도 낮아지기 때문이에요. for 문에 조건식만 넣으면 바로 while 문이 되므로 기능적으로 부족함이 전혀 없어요.

Q. range 문에서 인덱스만 쓰고 싶을 때는 어떻게 하나요?

언더스코어(_) 기호를 사용하면 돼요. for _, value := range mySlice라고 작성하면 인덱스는 버리고 값만 가져올 수 있어요. Go에서 사용하지 않는 변수를 선언하면 에러가 나기 때문에 이 방법이 필수적이에요.

Q. 무한 루프를 돌릴 때 CPU 점유율이 너무 높아요. 방법이 없을까요?

조건 없이 계속 도는 루프는 CPU 자원을 엄청나게 소모해요. 루프 중간에 time.Sleep() 함수를 넣어 아주 짧은 시간이라도 휴식 시간을 주면 CPU 부하를 크게 줄일 수 있어요.

Q. break와 return의 차이점이 무엇인가요?

break는 현재 실행 중인 '루프'만 탈출하지만, return은 루프를 포함한 현재의 '함수' 전체를 종료하고 호출한 곳으로 돌아가요. 상황에 맞는 적절한 선택이 필요해요.

Q. 슬라이스를 순회할 때 값을 직접 수정하면 원본도 바뀌나요?

네, 바뀌어요. range에서 반환하는 값은 요소의 복사본이에요. 만약 원본 슬라이스의 내용을 바꾸고 싶다면 값 대신 인덱스를 사용하여 mySlice[i] = newValue와 같이 접근해야 해요.

반복문 마스터를 위한 마지막 정리

지금까지 Go 언어의 유일한 반복문인 for의 모든 것을 살펴보았어요. 처음에는 생소할 수 있지만, 익숙해지면 이보다 명확하고 강력한 도구도 없다는 것을 느끼게 될 거예요. 반복문은 프로그래밍의 가장 기초적인 벽이자, 동시에 성능을 결정짓는 핵심 열쇠라는 점을 잊지 마세요.

✅ 핵심 요약

  • Go는 오직 for 키워드 하나로 모든 반복을 수행해요.
  • 표준형, 조건식 전용, 무한 루프, range 순회 4가지 패턴을 숙지하세요.
  • break는 루프 탈출, continue는 다음 반복으로 건너뛰기를 의미해요.
  • range를 쓸 때는 인덱스와 값의 순서, 맵의 무작위 순서에 주의하세요.
  • 중첩 루프는 성능 저하의 주범이 될 수 있으니 항상 경계하세요.

오늘 배운 내용을 바탕으로 바로 실습에 도전해 보세요. 이론으로 아는 것과 직접 타이핑하며 에러를 만나는 것은 하늘과 땅 차이예요. 다음 단계를 위해 아래의 미션을 제안할게요.

  • 오늘 할 일: 표준형 for 문을 사용하여 1부터 100까지의 숫자 중 3의 배수만 출력하는 코드를 작성해 보세요.
  • 이번 주 할 일: 슬라이스와 맵을 만들고, 각각 range 문을 사용하여 데이터를 순회하며 특정 값을 찾는 로직을 구현해 보세요.
  • 실행 직전 할 일: 내가 짠 루프에 무한 루프의 위험은 없는지, 탈출 조건이 명확한지 다시 한번 검토하세요.

반복문을 자유자재로 다룰 수 있게 되었다면, 여러분은 이미 Go 개발자로서 한 단계 성장한 거예요. 다음 편에서는 Go의 꽃이라고 불리는 고루틴(Goroutine)과 채널(Channel)을 활용한 병렬 프로그래밍에 대해 다룰 예정이에요. 반복문만큼이나 강력한 동시성 제어의 세계가 기다리고 있으니, 구독하고 놓치지 마세요!

관련 글: Go 기본 문법 가이드 - 변수와 데이터 타입 이해하기

댓글 남기기