본문으로 바로가기

[Golang] for문

category ProgrammingGo 2년 전

for문 동작 원리

  • Go언어는 반복문으로 for문 하나만 지원한다.
    • 하지만 여러가지 형태가 있기 때문에 적재적소에 잘 사용해야 한다.

형식

for 초기문; 조건문; 후처리 {
		코드 블록 // 조건문이 true인 경우 수행됨.
}

동작 순서

  1. 초기문이 먼저 실행됨.
  2. 조건문을 검사함.
    • if 조건문이 true?
      1. for문 { } 안쪽 코드 블록 수행
      2. 후처리 구문 실행
    • if 조건문이 false?
      1. for문 종료

다양한 형태

1️⃣ 초기문 생략

for ; 조건문; 후처리 {
	코드 블록
}

초기문을 생략해도 ;를 붙여서 조건문 자리를 표시해줘야 한다.

2️⃣ 후처리 생략

for 초기문; 조건문; {
	코드 블록
}

후처리를 생략해도 조건문 뒤에 ;를 붙여줘야 한다.

3️⃣ 조건문만 있는 경우

형식 1

for ; 조건문; {
	코드 블록
}

형식 2

for 조건문 {
	코드 블록
}

4️⃣ 무한 루프

형식 1

for true {
	코드 블록
}

조건문이 true이면 무한 루프가 된다.

형식 2

for {
	코드 블록
}

switch문과 마찬가지로 true를 생략할 수 있다.

continue와 break

  • continue : 이후 코드 블록을 수행하지 않고 곧바로 후처리를 하고 조건문 검사부터 다시한다.
  • break : for문에서 곧바로 빠져 나온다.

예제

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	stdin := bufio.NewReader(os.Stdin)
	for { // ❶ 무한 루프
		fmt.Println("입력하세요")
		var number int
		_, err := fmt.Scanln(&number) // ❷ 한줄 입력을 받습니다.
		if err != nil {               // ❸ 숫자가 아닌 경우
			fmt.Println("숫자를 입력하세요")

			// 키보드 버퍼를 비웁니다.
			stdin.ReadString('\\n') // ❹ 키보드 버퍼를 지워줍니다.
			continue               // ➎ ❶ 로 돌아갑니다
		}
		fmt.Printf("입력하신 숫자는 %d입니다\\n", number)
		if number%2 == 0 { // ➏ 짝수 검사를 합니다.
			break // ➐ for문을 종료합니다.
		}
	}
	fmt.Println("for문이 종료되었습니다.")
}

중첩 for문

for문을 중첩해서 사용할 수 있다.

예제 1

package main

import "fmt"

func main() {
	for i := 0; i < 3; i++ { // ❶ 3번 반복합니다.
		for j := 0; j < 5; j++ { // ❷ 5번 반복합니다.
			fmt.Print("*") // ❸ * 를 출력합니다.
		}
		fmt.Println() // ❹ 줄바꿈합니다.
	}
}
중첩 반복문을 사용하면 연산량이 크게 증가되므로 사용에 주의해야 한다.

예제 2

package main

import "fmt"

func main() {
	for i := 0; i < 5; i++ { // ❶ 5번 반복합니다.
		for j := 0; j < i+1; j++ { // ❷ 현재 i값+1만큼 반복합니다.
			fmt.Print("*") // ❸ *를 출력합니다.
		}
		fmt.Println() // ❹ 줄바꿈합니다.
	}
}

예제 3 continue와 break를 사용

package main

import "fmt"

func main() {
	dan := 2
	b := 1
	for {
		for {
			fmt.Printf("%d * %d = %d\\n", dan, b, dan*b)
			b++
			if b == 10 { // ❶
				break // 안쪽 for문을 종료합니다.
			}
		}
		b = 1
		dan++
		if dan == 10 { // ❷
			break // 바깥쪽 for문을 종료합니다.
		}
	}
	fmt.Println("for문이 종료되었습니다.")
}
  • for문을 중첩하여 구구단을 출력한다.

중첩 for문과 break, 레이블

앞의 예제들은 break가 속한 for문에서만 빠져나온다.

모든 for문을 빠져나가고 싶을 때는 어떻게 해야 할까?

예제 1 플래그 (Flag) 변수 사용

package main

import "fmt"

func main() {
	a := 1
	b := 1

	found := false
	for ; a <= 9; a++ {
		for b = 1; b <= 9; b++ {
			if a*b == 45 {
				found = true // ❶ 찾았음을 표시하고 break
				break
			}
		}
		if found { // ❷ 바깥쪽 for문에서 찾았는지 검사해서 break
			break
		}
	}
	fmt.Printf("%d * %d = %d\\n", a, b, a*b)
}
  • 1~9 사이의 두 수를 곱했을 때 45가 되는 수를 찾는다.
  • 안쪽 for문에서 두 수의 곱이 45가 되는 경우를 찾았으면 안쪽 for문을 종료한다.
    • 이 때 바깥쪽의 for문은 종료되지 않았으므로 found가 ture인지 검사하고 for문을 종료해야 한다.

이런 형태로 boolean 변수를 사용하는 것을 플래그(Flag) 변수라고한다.

그러나 이런 플래그 변수 사용하는 것은 번거로울 수 있음. (삼중, 사중 for문 이면 복잡..)

예제 2 레이블

package main

import "fmt"

func main() {
	a := 1
	b := 1

OuterFor:
	for ; a <= 9; a++ {
		for b = 1; b <= 9; b++ {
			if a*b == 45 {
				break OuterFor
			}
		}
	}
	fmt.Printf("%d * %d = %d\\n", a, b, a*b)
}

for문을 시작할 때 레이블을 정의하고 break할 때 정의한 레이블을 적어준다면 그 레이블에서 가장 먼저 속한 for문까지 모두 종료하게 된다.

  • 레이블은 레이블 이름을 적고 콜론 : 을 적어서 정의한다.

그러나 레이블 방법은 편리할 수 있으나 다음의 단점이 존재한다.

  1. 혼동을 불러일으킬 수 있음.
  2. 예기치 못한 버그가 발생할 수 있음.
따라서 되도록 플래그를 사용하고 레이블은 꼭 필요한 경우에만 사용하기를 권장한다.

클린코드

  1. 중첩된 내부 로직을 함수로 묶어서 중첩을 줄이고
  2. 플래그 변수나 레이블 사용을 최소화 해야한다.

예제

package main

import "fmt"

func find45(a int) (int, bool) { // ❶ 곱해서 45가 되는 값을 찾는다
	for b := 1; b <= 9; b++ {
		if a*b == 45 {
			return b, true
		}
	}
	return 0, false
}

func main() {
	a := 1
	b := 0

	for ; a <= 9; a++ {
		var found bool
		if b, found = find45(a); found { // ❷ 함수 호출
			break
		}
	}
	fmt.Printf("%d * %d = %d\\n", a, b, a*b)
}

ProgrammingGo카테고리의 다른글

[Golang] 구조체 (Structure)  (1) 2022.11.13
[Golang] 배열 (Array)  (0) 2022.11.12
[Golang] Switch문  (0) 2022.11.06
[Golang] if문  (0) 2022.11.06
[Golang] 상수 (Const)  (0) 2022.10.29