For, If, Switch 에 대하여 알아보자.
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
}
만약 배열, 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
마지막으로 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]
}
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)
}
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 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.")
}
스위치 구문은 인터페이스(추후에 설명) 변수의 동적 타입을 확인하는데 사용될 수도 있다.
이때 괄호안에 키워드 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
}