[GO] #2-3. 고랭 기본문법 (제어구문)

Study·2021년 5월 17일
0

고랭

목록 보기
4/18
post-thumbnail

제어구문

For, If, Switch 에 대하여 알아보자.

1. For

1-1. For 기초

GO 는 while 과 do-while 은 배제하여 for 반복문이라는 하나의 반복 구조만을 가진다.

기본적으로 for 반복문에 세미콜론을 이용해 구별되는 세 가지 요소를 갖는다.

1. init (초기화 구문)	: 첫 번재 iteration 전에 수행
2. condition (조건 표현)	: 두매 모든 iteration 이전에 판별
3. post (사후 구문)	: iteration 마지막에 수행

초기화 구문은 짧은 변수 선언이 관례이며, 이 변수들은 for 문 스코프 내에서만 보여진다.

반복문은 조건 판별의 boolean 값이 false 라면 iterating 을 종료한다.

주의 사항으로는 다른 언어와 달리 세 가지 구성 요소를 감싸는 괄호가 없고, { } 괄호가 항상 필수이다.

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

초기화와 사후 구문은 필수는 아니다. 그래서 while 처럼 동작할 수 있다.

하지만 do-while 문은 없다.

// C언어와 같은 경우
for init; condition; post { }
// C언어의 while 처럼 사용
for condition { }
// C언어의 for(;;) 무한 반복문 처럼 사용
for { }

이를 활용하면 while 문을 다음과 같이 작성할 수 있다.

sum := 1
for sum < 1000 {
	sum += sum
}

1-2. range

만약 배열, slice, string, map, 채널로 부터 읽어 들이는 반복문을 작성한다면, range 구문이 반복문을 관리해줄 수 있다.

for key, value := range oldMap {
	newMap[key] = value
}

만약 range 안에서 두 번째 아이템만이 필요하면 공백 식별자, 언더스코어를 사용하여 첫 번째를 버릴 수 있다.

sum := 0
for _, value := range array {
    sum += value
}

공백 식별자가 이전 챕터와 현재 챕터에도 나오는데 추후에 설명하겠다.

string 의 경우, range는 UTF-8 파싱으로 개별적인 유니코드 문자를 처리한다.

for pos, char := range "안녕하세요.♥" {
	fmt.Printf("charagter %#U starts at byte position %d\n", char, pos)
}

실행 결과는 다음과 같다.

charagter U+C548 '안' starts at byte position 0
charagter U+B155 '녕' starts at byte position 3
charagter U+D558 '하' starts at byte position 6
charagter U+C138 '세' starts at byte position 9
charagter U+C694 '요' starts at byte position 12
charagter U+002E '.' starts at byte position 15
charagter U+2665 '♥' starts at byte position 16

1-3. 여러 개의 변수 할당

마지막으로 Go 언어는 콤마(,) 연산자가 없으며 ++, -- 는 표현식이 아닌 명령문이다.

그래서 for 문 안에서 여러개의 변수를 사용하려면 병렬 할당(parallel assignment)을 사용해야만 한다

// a 배열 리버스
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
    a[i], a[j] = a[j], a[i]
}

2. If

Go 의 if 문은 반복문과 비슷하게 ( ) 괄호는 필요없지만, { } 괄호는 필수다.

가장 간단한 예시로 다음을 들 수 있다.

if x > 0 {
    return y
}

for 문과 마찬가지로, if 문 또한 조건문 전에 수행될 짧은 구문으로 시작할 수 있다.

이 짧은 구문에서 선언된 변수의 스코프는 if 문의 끝까지만 존재한다.

func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}

짧은 if 문 안에서 선언된 변수들은 어떠한 else 블럭이든 사용이 가능하다.

다음은 pow 함수로 할당한 변수를 지속적으로 사용하는 모습을 보여준다.

if v := math.Pow(x, n); v < lim {
	return v
} else {
	fmt.Printf("%g >= %g\n", v, lim)
}

3. Switch

Go 에서 스위치문은 C 언어보다 더 일반적인 표현이 가능하다.

표현식은 상수이거나 꼭 정수일 필요가 없으며 true 가 아닌 동안 일치하는 값을 찾을 때까지 계속 값을 비교한다.

모든 case 를 실행하는 것이 아닌 오직 첫 번째로 선택된 케이스만을 실행한다는 점을 제외하면 다른 언어와 유사하다.

이는 GO 에서 자동으로 break 가 제공되어 GO 언어다운 Switch 를 작성할 수 있다.

func unhex(c byte) byte {
    switch {
    case '0' <= c && c <= '9':
        return c - '0'
    case 'a' <= c && c <= 'f':
        return c - 'a' + 10
    case 'A' <= c && c <= 'F':
        return c - 'A' + 10
    }
    return 0
}

물론 switch 문을 일찍 종료하기 위해서 break 문을 명시할 수 있다.

switch {
	case src[n] < sizeOne:
		if validateOnly {
			break
		}
		size = 1
		update(src[n])
        case src[n] < sizeTwo:
			if n+1 >= len(src) {
				err = errShortInput
				break Loop
			}
			if validateOnly {
				break
			}
			size = 2
			update(src[n] + src[n+1]<<shift)
	}

자동으로 다음으로 통과하는 동작이 없는 대신, 콤마로 구분된 목록을 사용하여 case 들을 표현할 수 있다.

func shouldEscape(c byte) bool {
    switch c {
    case ' ', '?', '&', '=', '#', '+', '%':
        return true
    }
    return false
}

조건 없는 Switch

조건이 없는 Switch 는 switch true 와 동일하다.

이 구조는 긴 if-else 체인을 사용하는 데에 깔끔한 방식으로 사용될 수 있다.

switch {
case t.Hour() < 12:
	fmt.Println("Good morning!")
case t.Hour() < 17:
	fmt.Println("Good afternoon.")
default:
	fmt.Println("Good evening.")
}

타입 Switch

스위치 구문은 인터페이스(추후에 설명) 변수의 동적 타입을 확인하는데 사용될 수도 있다.

이때 괄호안에 키워드 type 을 사용한다.

스위치 표현식 안에 변수를 선언한다면, 변수는 각각의 절에 일치하는 타입을 가질 것이다.

사실 각 절 안에서 새 변수를 다른 타입이지만 동일한 이름으로 선언하는 것과 각 절 안에서 이름을 재사용하는 것이 관례적이다.

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T\n", t)     // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}
profile
Study

0개의 댓글