본문 바로가기

golang

golang5 조건문과 반복문

반복문

golang은 반복문은 오직 for syntax만 제공해준다. 그래서 while문법을 이용하기 위해선 for문을 변형을 수행하여야 한다.

for문의 구조는 다른 언어들과 큰 차이가 없다.

for i := 0; i < 10; i++ {
    fmt.Printf("i: %d\n", i)
}

차례대로 초기식;조건식;변화식 구조를 가진다. 초기식에서 선언된 변수는 for 문 내에서만 유효하다.

위의 기본 식들을 이용하여 다음과 같이 응용할 수 있다.

1. while syntax

다른 언어처럼 조건식만 작성해서 while문을 만들 수 있다.

var j = 0
for j > 10 {
    fmt.Printf("j: %d\n", j)
    j--
}

조건식만 작성해서 while문을 작성한다.

위의 코드에서 j-- 수식을 변화식에 작성해서 다음과 같이 작성할 수 있다.

var j = 0
for ;j > 10; j-- {
	fmt.Printf("j: %d\n", j)
}

2. 무한루프

for문에 초기식, 조건식, 변화식을 모두 작성하지 않는다. 이를 통해 종료조건 없이 계속 반복되는 무한 루프를 만들 수 있다.

	var k = 10
	for {
		fmt.Printf("k: %d\n", k)
		if k < 0 {
			fmt.Println("break")
			break
		}
		k--
	}

3. for-each

가장 많이 사용되는 문법인 for-each도 작성이 가능하다. golang에선 이 문법을 for range syntax로 불린다.

range는 collection객체를 순회한다.

range를 통해 collection에서 element를 참조해서 index와 value값을 가져온다. 단 value는 원본이 아닌 복사된 값이다.

arr := [...]int{1, 2, 3, 4, 5}
for idx, value := range arr {
    fmt.Printf("%d: %d\n", idx, value)
}

range를 사용 할 수 있는 조건은 다음과 같다.

  1. slice
    • idx, value형태로 반환
  2. map
    • key, value형태
  3. string
    • 문자열에서 현재 순회중인 문자의 유니코드 시작 위치(int), utf-8로 인코딩된 문자(type: rune)
  4. channel
    • 채널을 닫을 때까지 보낸 모든 데이터
    • nil 채널일 경우 무한루프로 동작함

여기서 3번에 대해선 좀 더 자세히 볼 필요가 있다. 이유는 다른 언어의 string과의 차이점이 존재하기 때문이다.

golang의 string은 문자들을 byte단위로 쪼개서 저장된다.

golang은 문자를 utf-8로 인코딩하여 byte단위로 저장된다 즉 golang은 문자열을 utf-8인코딩 수행 후 byte단위로 쪼개서 저장한다. 다음의 코드를 보자

	for idx, value := range "apple😊 사과" {
		fmt.Printf("%d: %U\n", idx, value)
	}

영어, 한글, 이모지가 포함된 문자열이다. 영어는 아스키 코드 범위 내이 포함되어 있으므로 1byte로 표현가능하다. 그러나 한글과 유니코드는 2byte이상으로 표현가능한 문자다. 이를 인지한 상태로 코드의 수행 결과를 보자.

실행결과

idx를 출력하는 부분을 보면 영어일때는 순차적으로 증가하다가 한글, 이모지를 만날 경우 값이 많이 증가한다. idx는 문자의 유니코드 시작 위치이다. 한글과 유니코드는 2byte이상의 글자이므로 idx가 2이상으로 증가한 것을 알 수 있다. 이는 해당 문자열을 byteArray로 변환하면 명확히 알 수 있다.

실행결과

코드에서 실행한 문자열의 구조를 그림으로 그리면 다음과 같다.

구조

위의 구조를 가지므로 idx가 0,1,2,3,4.5.9.10,13 순으로 출력이 된다. 그럼 문자열 기준으로 idx를 출력시키고 싶으면 어떻게 수행해야 할까? 간단하다. rune타입 Array로 타입캐스팅을 수행하면 가능하다.

	var str = "apple😊 사과"
	for idx, value := range []rune(str) {
		fmt.Printf("%d: %U\n", idx, value)
	}
	var runeArray = []rune(str)
	fmt.Println(runeArray)

실행결과

문자기준으로 인덱스가 잡히는 것을 알 수 있다.

제어문

다른 언어 처럼 반복문을 제어할 수 있는 예약어 continue, break들이 존재한다. goto라는 clang의 goto와 같은 역할을 수행하는 예약어도 있지만 사용되진 않는다.


조건문

golang의 조건문은 다른 언어들에도 존재하는 if-else와 switch 그리고 select문이 존재한다. 다만 select는 고루틴에서 사용되는 switch문이므로 고루틴을 설명할 때 따로 기술하겠다.

if-else syntax

여타 다른 언어들에서 본 것 처럼 사용법은 동일하다.

	var num1 = 10
	var num2 = 20

	if num1+num2 > 20 {
		fmt.Println("20 초과")
	} else if num1+num2 == 20 {
		fmt.Println("20")
	} else {
		fmt.Println("20미만")
	}

그러나 golang만의 특징이라면 조건문 내에서 간단한 명령을 실행시킬 수 있다.

여기서 간단한 명령이란 1줄짜리 명령을 의미한다.

	var num1 = 10
	var num2 = 20

	if result := num1 + num2; result > 20 {
		fmt.Println("20 초과")
	} else if result == 20 {
		fmt.Println("20")
	} else {
		fmt.Println("20미만")
	}

result라는 변수에 num1과 num2의 합연산 결과를 저장하고 result변수의 결과로 조건문을 수행한다. result변수의 scope는 조건문 내에서만 유효하다.

switch syntax

여타 다른 언어들에서 보았던 switch의 기능을 제공한다.

	var num1 = 10
	var num2 = 20

	switch num1 + num2 {
	case 20:
		fmt.Println("20")
	default:
		fmt.Println("20이 아님")
	}

case내에 break를 작성해줄 필요가 없으므로 위의 코드처럼 작성될 수 있다.

golang만의 switch특징은 다음과 같다.

1. case 조건

golang의 case는 정수가 아니여도 상관없다. 그래서 다음과 같이 작성될 수 있다.

	var float1 = 0.2
	var float2 = 15.3
	switch float1 + float2 {
	case 15:
		fmt.Println("15")
	case 16:
		fmt.Println("16")
	case 15.5:
		fmt.Println("15.5")
	default:
		fmt.Println("default")
	}

여러개의 케이스들을 나열할 수 있으며 if조건문과 마찬가지로 switch조건식에 1줄짜리 코드를 실행시킬 수 있다.

func add(num1, num2 int) int {
	switch result := num1 + num2; result {
	case math.MaxInt, math.MinInt:
		panic("Overflow or Underflow!!!")
	default:
		fmt.Println(result)
		return result
	}
}

밑에서 설명할 switch true를 작성하면 조건식을 포함시킬 수 있다.

switch true

golang의 switch엔 조건식 없이 작성될 수 있다. 이 기능을 switch true라고 불린다. 이유는 조건식이 없으면 true로 인지하기 때문이다.

	switch {
	case true:
		fmt.Println("15")
	default:
		fmt.Println("default")
	}

위의 코드에서 switch의 조건식이 없다. 그러므로 항상 case true의 내용만 실행된다.

그럼 이 기능은 왜 있을까? 바로 조건식을 간결하게 만들기 위해서이다.

다음의 코드를 보자.

func menuHour(hour int) {
	switch {
	case hour >= 9 && hour < 12:
		fmt.Println("오전")
	case hour >= 12 && hour < 13:
		fmt.Println("점심")
	case hour >= 13 && hour < 18:
		fmt.Println("오후")
	case hour >= 18 && hour < 24:
		fmt.Println("퇴근")
	default:
		fmt.Println("출.근.싫.어.")
	}
}

if, else if 역할을 case가, else 역할을 default가 수행한다.

'golang' 카테고리의 다른 글

golang7 slice  (0) 2022.01.09
golang6 구조체  (0) 2021.12.26
golang4 함수  (0) 2021.12.24
golang3 변수와 상수  (0) 2021.12.23
golang1 연산자  (0) 2021.12.19