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

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

반복문 for, 왜 Go에서는 이것 하나로 충분할까요?

새벽 2시, 야심 차게 작성한 코드를 실행했는데 프로그램이 응답 없이 멈춰버린 적이 있으신가요? 터미널에는 아무런 에러 메시지도 뜨지 않고, CPU 점유율만 치솟는 상황이라면 십중팔구 무한 루프에 빠진 거예요. Go 반복문 치트시트를 제대로 이해하지 못한 상태에서 복잡한 로직을 짜다 보면 누구나 마주하게 되는 당혹스러운 순간이죠.

다른 프로그래밍 언어에서는 while이나 do-while 같은 다양한 반복문이 존재하지만, Go는 오직 for 하나로 모든 것을 해결해요. 처음에는 이게 불편하게 느껴질 수도 있지만, 사실 이것은 언어를 최대한 단순하게 유지하여 가독성을 높이려는 Go의 철학이 담긴 설계랍니다. 단순하다고 해서 기능이 부족한 것은 결코 아니에요.

이 글을 끝까지 읽고 나면, 여러분은 복잡한 컬렉션을 자유자재로 다루고 상황에 맞는 가장 효율적인 반복 패턴을 선택할 수 있게 될 거예요. 단순히 문법을 암기하는 수준을 넘어, 실제 프로덕션 환경에서 발생할 수 있는 성능 문제와 실수까지 방지하는 능력을 갖추게 됩니다.

💡 알아두기
이 글은 Go를 처음 접하는 입문자를 위해 작성되었으며, 기초 문법부터 실전 활용 팁까지 단계별로 구성했어요.

이번 가이드에서 함께 살펴볼 핵심 내용은 다음과 같아요.

  • Go 반복문의 기본 구조와 C-스타일 문법
  • 슬라이스, 맵, 문자열을 순회하는 range 활용법
  • break와 continue를 활용한 흐름 제어와 레이블 사용법
  • 입문자가 가장 많이 하는 실수와 해결 방안

반복문을 시작하기 전 꼭 알아야 할 기초 지식

반복문을 본격적으로 작성하기 전에, Go 언어만의 독특한 특징을 먼저 이해해야 해요. Go에는 while 문이 없습니다. 모든 반복 로직은 for 키워드 하나로 구현해야 한다는 뜻이에요. 이는 코드의 일관성을 높여주지만, 기존 언어에 익숙한 개발자에게는 약간의 적응 기간이 필요할 수 있어요.

반복문을 설계할 때는 단순히 ‘어떻게 돌릴까’만 생각해서는 안 돼요. 내가 다루려는 데이터가 슬라이스(Slice)인지, 맵(Map)인지, 아니면 일반적인 숫자인지에 따라 최적의 문법이 달라지거든요. 잘못된 선택은 프로그램의 성능을 저하시키거나 예상치 못한 버그를 유발할 수 있어요.

반복 유형별 선택 기준 비교

반복 방식 주요 사용처 장점 주의점
기본 for 인덱스 기반 제어, 특정 간격 반복 정밀한 제어 가능 조건식 오류 시 무한 루프 위험
range 활용 슬라이스, 맵, 문자열 순회 코드 가독성 극대화 값의 복사 발생 가능성
조건식 for while 문 대체, 상태 기반 반복 유연한 종료 조건 상태 업데이트 누락 주의

반복문을 작성하기 전에 반드시 확인해야 할 체크리스트를 정리해 드릴게요. 이 리스트를 따라가다 보면 더 견고한 코드를 작성할 수 있어요.

  • 종료 조건이 명확한가? 루프가 반드시 끝날 수 있는 장치가 마련되어 있는지 확인하세요.
  • 데이터 타입을 확인했는가? 맵을 순회할 때는 순서가 보장되지 않는다는 점을 인지해야 해요.
  • 불필요한 복사는 없는가? 큰 구조체를 range로 돌릴 때는 인덱스만 사용하는 것이 유리할 수 있어요.
⚠️ 주의
슬라이스의 길이를 실시간으로 변경하면서 반복문을 돌리면 인덱스 범위 초과(Index out of range) 오류가 발생할 가능성이 매우 높아요. 데이터 삭제가 필요하다면 역순으로 순회하는 기법을 고려하세요.

Go 반복문 실전 패턴 완벽 가이드

이제 본격적으로 Go 반복문 치트시트의 핵심 내용을 살펴볼게요. 실전에서 바로 복사해서 사용할 수 있을 만큼 구체적인 패턴들로 구성했어요.

STEP 1. 전통적인 C-스타일 for 문 활용하기

가장 기본적인 형태의 반복문이에요. 초기화, 조건식, 증감식을 한 줄에 작성하여 루프의 시작과 끝을 한눈에 파악할 수 있어요. 특정 숫자를 카운트하거나, 인덱스를 직접 조작해야 할 때 아주 유용해요.

예를 들어, 1부터 10까지의 합을 구하는 코드는 다음과 같아요.

for i := 1; i <= 10; i++ { sum += i }

여기서 주의할 점은 조건식의 경계값이에요. `<=`를 쓸지 `<`를 쓸지에 따라 루프가 한 번 더 돌거나 덜 돌 수 있으니, 슬라이스의 길이를 다룰 때는 항상 len(slice)과의 관계를 명확히 해야 해요. 이 방식은 인덱스를 2씩 증가시키거나(예: `i += 2`), 역순으로 진행할 때도 매우 강력한 힘을 발휘합니다.

STEP 2. range를 이용한 컬렉션 순회 마스터하기

Go 개발자가 가장 많이 사용하는 방식이에요. 슬라이스, 배열, 맵, 문자열을 다룰 때 range 키워드를 사용하면 코드가 놀라울 정도로 간결해져요.

슬라이스와 배열에서는 인덱스와 값을 동시에 가져올 수 있어요. 만약 값만 필요하다면 인덱스 자리에 언더스코어(_)를 써서 무시하면 됩니다. 하지만 여기서 성능 최적화 팁 하나를 드릴게요. 매우 큰 구조체 슬라이스를 순회할 때 for i, v := range slice라고 쓰면 매 반복마다 구조체 전체가 복사되어 메모리 효율이 떨어질 수 있어요. 이럴 때는 for i := range slice로 인덱스만 가져온 뒤, slice[i]로 직접 접근하는 것이 훨씬 빠릅니다.

맵(Map) 순회는 조금 결이 달라요. 맵을 range로 돌리면 (Key, Value) 쌍을 반환해요. 하지만 맵은 순서가 없는 자료구조라는 점을 절대 잊지 마세요! 실행할 때마다 결과 순서가 달라질 수 있으므로, 일관된 순서가 필요하다면 키(Key)를 먼저 슬라이스에 담아 정렬한 뒤 순회해야 합니다.

문자열 순회의 경우, range는 바이트가 아닌 Rune(유니코드 코드 포인트) 단위로 문자를 가져와요. 덕분에 한글 같은 다국어 문자열도 깨지지 않고 안전하게 하나씩 읽어낼 수 있어요.

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

Go에는 while 키워드가 따로 없지만, for 문에 조건식만 넣으면 완벽하게 똑같은 기능을 수행해요. 상태가 특정 조건에 도달할 때까지 계속해서 작업을 수행해야 하는 경우에 사용합니다.

예를 들어, 데이터베이스에서 더 이상 읽을 데이터가 없을 때까지 데이터를 가져오는 로직은 다음과 같이 작성할 수 있어요.

for hasMoreData { // hasMoreData가 true인 동안 계속 실행 }

이 방식은 조건이 거짓이 되는 순간 즉시 종료되므로, 로그 파일의 끝을 읽거나 네트워크 소켓으로부터 데이터를 수신하는 등 비동기적인 상황을 처리할 때 매우 핵심적인 역할을 해요.

STEP 4. break와 continue로 흐름 정교하게 제어하기

반복문 내부에서 특정 상황에 따라 흐름을 끊거나 건너뛰어야 할 때가 있죠. 이때 breakcontinue를 사용해요.

  • continue: 현재 반복의 남은 코드를 실행하지 않고 즉시 다음 반복 회차로 넘어갑니다. (예: 특정 조건의 데이터만 필터링하고 싶을 때)
  • break: 반복문을 완전히 탈출합니다. (예: 원하는 데이터를 찾았을 때 루프를 즉시 종료하고 싶을 때)

심지어 중첩된 루프(Nested Loop)에서 바깥쪽 루프까지 한꺼번에 탈출하고 싶다면 레이블(Label) 기능을 사용할 수 있어요. OuterLoop: for ... { for ... { break OuterLoop } }와 같이 작성하면, 안쪽 루프에서 바깥쪽 루프를 지정해 단번에 빠져나갈 수 있답니다.

STEP 5. 실전 시나리오: 사용자 데이터 처리하기

이 모든 것을 종합한 실전 예시를 살펴볼게요. 사용자 목록 슬라이스에서 특정 등급 이상의 사용자만 골라내어 처리하는 시나리오입니다.

// 사용자 구조체 정의
type User struct { Name string; Grade int }

// 사용자 목록
users := []User{{"Kim", 1}, {"Lee", 5}, {"Park", 3}, {"Choi", 8}}

// 특정 등급 이상만 처리하는 루프
for i := range users {
if users[i].Grade < 3 {
continue // 등급이 낮으면 건너뜀
}
fmt.Printf("우수 사용자 발견: %s\n", users[i].Name)
if users[i].Grade >= 7 {
break // 최고 등급을 찾으면 루프 종료
}
}

위 코드는 인덱스 기반 순회를 사용하여 복사 비용을 줄였고, continue로 불필요한 로직을 건너뛰었으며, break로 효율적인 종료를 구현했습니다. 이것이 바로 실전에서 요구되는 Go 반복문 치트시트의 활용 능력이에요.

자주 하는 실수와 해결법

실력 있는 개발자와 초보자의 차이는 실수를 하지 않는 것이 아니라, 실수를 어떻게 빠르게 인지하고 해결하느냐에 달려 있어요. Go 반복문에서 흔히 발생하는 실수들을 정리해 드릴게요.

  • 실수: 인덱스 범위 초과 (Index out of range)
    왜 발생하는가: 루프 조건식에 i <= len(slice)처럼 등호를 잘못 사용했기 때문이에요.
    해결법: 반드시 i < len(slice)와 같이 미만 조건을 사용하세요.
  • 실수: 루프 변수 포인터 문제
    왜 발생하는가: range로 가져온 변수의 주소값을 슬라이스에 저장할 때, 모든 요소가 마지막 요소의 주소만 가리키게 되는 현상이에요.
    해결법: 루프 내부에서 변수를 새로 선언하거나, 인덱스를 사용하여 값을 직접 복사하세요.
  • 실수: 맵 순회 시 순서 의존
    왜 발생하는가: 맵은 내부적으로 해시 테이블을 사용하므로 순서가 보장되지 않아요.
    해결법: 순서가 중요하다면 키를 별도의 슬라이스에 담아 정렬한 후 순회하세요.
  • 실수: 무한 루프 발생
    왜 발생하는가: while 스타일 루프에서 조건을 변화시키는 코드를 누락했기 때문이에요.
    해결법: 루프 몸체 안에 탈출 조건을 만족시키는 로직이 반드시 포함되어 있는지 확인하세요.
  • 실수: 슬라이스 요소 삭제 중 순회
    왜 발생하는가: 요소를 삭제하면 슬라이스의 길이가 줄어들어 인덱스가 꼬이게 됩니다.
    해결법: 뒤에서부터 앞으로 순회(역순 순회)하면 인덱스 영향을 받지 않고 안전하게 삭제할 수 있어요.

자주 묻는 질문

Q. Go에서 while 문을 쓰고 싶은데 어떻게 해야 하나요?

Go에는 while 키워드가 없지만, for condition { ... } 형식을 사용하면 while과 완전히 똑같이 동작합니다. 매우 간단하죠?

Q. range를 사용할 때 인덱스와 값을 모두 가져오지 않으면 에러가 나나요?

아니요, 에러는 나지 않아요. 다만 인덱스만 필요하다면 for i := range slice라고 쓰면 되고, 값만 필요하다면 for _, v := range slice처럼 언더스코어를 사용하여 인덱스를 무시하면 됩니다.

Q. 중첩 루프에서 바깥쪽 루프까지 한 번에 깨고 싶을 때 가장 좋은 방법은 무엇인가요?

Go의 레이블(Label)을 사용하는 것이 가장 깔끔하고 'Go다운' 방식이에요. 다른 언어처럼 플래그 변수를 만들어 체크하는 방식보다 가독성이 훨씬 높습니다.

Q. 문자열을 한 글자씩 읽을 때 왜 byte가 아니라 rune을 써야 하나요?
한글 같은 유니코드 문자는 한 글자가 여러 바이트로 구성될 수 있기 때문이에요. range를 쓰면 Go가 알아서 rune 단위로 끊어서 읽어주므로 글자가 깨지지 않아요.

마치며: 반복문 정복을 위한 마지막 단계

오늘 우리는 Go 반복문 치트시트를 통해 기초부터 심화 패턴까지 살펴보았습니다. 반복문은 단순해 보이지만, 어떻게 쓰느냐에 따라 코드의 성능과 유지보수성이 극명하게 갈리는 매우 중요한 도구예요.

✅ 핵심 요약

  • Go의 반복은 오직 for 하나로 모두 해결해요.
  • 컬렉션 순회 시에는 가독성이 좋은 range를 우선 고려하세요.
  • 대규모 구조체 순회 시에는 인덱스만 사용하는 것이 성능에 유리해요.
  • 맵은 순서가 보장되지 않으니 정렬이 필요하면 키를 따로 추출하세요.
  • 중첩 루프 탈출은 레이블을 활용하면 간결해져요.
  • 무한 루프를 방지하기 위해 종료 조건을 항상 검토하세요.

이제 이론은 충분해요. 직접 코드를 작성해 볼 시간입니다. 오늘 배운 내용을 바탕으로 다음 단계들을 실천해 보세요.

  • 오늘 할 일: Go Playground에서 슬라이스, 맵, 문자열을 각각 range로 돌려보는 코드를 3개 작성해 보세요.
  • 이번 주 할 일: 기존에 작성했던 프로젝트 코드 중 반복문이 들어간 부분을 찾아, 더 효율적인 패턴(예: 인덱스 직접 접근)으로 리팩토링해 보세요.
  • 실행 직전 할 일: 반복문 내부에서 포인터를 다룰 때 발생할 수 있는 버그를 방지하기 위해 변수 범위를 확인하는 습관을 들이세요.

반복문에 대해 더 깊이 있는 내용이 궁금하다면 Go 반복문 완전 정복 가이드 글을 함께 읽어 보시는 것을 추천해요. 공부하시다가 막히는 부분이나 궁금한 점은 언제든 댓글로 남겨 주세요. 여러분의 성장을 진심으로 응원합니다!

댓글 남기기