Go에서는 for와 인덱스를 사용해 slice를 순회할 수도 있고, range를 사용할 수도 있어요. range를 사용하면 map도 순회할 수 있어요.
각 반복은 두 개의 값을 반환해요. 인덱스/키와, 그 인덱스/키에 있는 원소의 복사본이에요.
아주 쉬워요. 슬라이스를 순회하면 예상한 순서대로 나와요.
xi := []int{10, 20, 30}
for i, x := range xi {
fmt.Println(i, x)
}
// outputs:
// 0, 10
// 1, 20
// 2, 30
맵을 순회할 때는 새로운 문제가 생겨요. 이제 순서가 무작위예요.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// outputs, for example:
// 99 20
// 999 30
// 9 10
위 출력이 잘못된 것처럼 보일 수 있어요. 맵을 선언할 때 처음 등장한 키/값 쌍인 9 10이 마지막이 아니라 가장 먼저 출력될 거라고 생각하기 쉽거든요. 하지만 맵은 본질적으로 순서가 없어요. 처음이나 마지막 키/값 쌍이라는 게 없어요. 그래서 맵의 항목을 순회할 때 방문하는 순서는 무작위이고, 특별한 규칙을 따르지 않아요. 즉, 위와 같은 출력이 나올 수도 있지만 직접 실행해 보면 결과가 다를 수도 있어요. 이에 대해 더 알아보려면 Go 언어 명세: range 절을 참고해요.
Go에서는 사용하지 않는 변수가 있으면 빌드할 때 오류가 발생해요. 첫 번째 예시처럼 값만 필요할 때도 있어요.
xi := []int{10, 20, 30}
for i, x := range xi {
fmt.Println(x)
}
// Go build failed: i declared but not used
i를 _로 바꾸면, 컴파일러에게 그 값을 사용하지 않는다고 알려 줄 수 있어요.
xi := []int{10, 20, 30}
for _, x := range xi {
fmt.Println(x)
}
// outputs:
// 10
// 20
// 30
인덱스만 출력하고 싶다면 x를 _로 바꾸거나, 선언 자체를 생략하면 돼요.
xi := []int{10, 20, 30}
// for i, _ := range xi {
for i := range xi {
fmt.Println(i)
}
// outputs:
// 0
// 1
// 2
타입 정의는 새로운 이름의 타입을 만들어요. 이 타입은 같은 기반 타입을 가지고 있더라도 다른 모든 타입과 구별되는 별개의 타입이에요.
type File []bool
여기서 File은 체스판의 세로줄 하나를 가리켜요. 보통 A부터 H까지 이름이 붙어 있죠. 이 세로줄에 있는 각 칸은 그 칸이 점유되었는지 아닌지를 나타내는 불리언 값으로 표현돼요. 이제 File이 정의되었으니 다른 정의 안에서도 사용할 수 있어요.
type Chessboard map[string]File
board := Chessboard{
"A": File{true, false, true},
"B": File{false, true, false},
}
Chessboard는 세로줄 식별자를 File 값에 대응시켜요. 각 File은 하나의 체스 세로줄에 있는 칸들을 나타내는 불리언 값의 슬라이스예요. 이런 타입 정의가 없다면 board는 map[string][]bool이 되어서, 무엇을 나타내는지 이해하기가 더 어려워졌을 거예요.
체스 애호가라면 누구나 자기만의 체스 게임을 만들어 보고 싶어 해요. 물론 온라인에는 이미 수많은 체스 구현이 있겠지만, 직접 만든 것은 세상에 하나뿐일 거예요!
체스판의 각 칸은 글자와 숫자 한 쌍으로 나타내요.
A B C D E F G H
8 # _ _ _ # _ _ # 8
7 _ _ _ _ _ _ _ _ 7
6 _ _ _ _ # _ _ # 6
5 _ # _ _ _ _ _ # 5
4 _ _ _ _ _ _ # # 4
3 # _ # _ _ _ _ # 3
2 _ _ _ _ _ _ _ # 2
1 # _ _ _ _ _ _ # 1
A B C D E F G H
CountInFile(board Chessboard, file string) int 함수를 구현해요.
맵을 순회하면서 점유된 칸의 총 개수를 세요.
정수를 반환해요.
주어진 파일이 맵에서 발견되지 않으면 0(0)을 반환해요.
CountInFile(board, "A")
// => 3
CountInRank(board Chessboard, rank int) int 함수를 구현해요.
주어진 랭크를 순회하면서 점유된 칸의 총 개수를 세요.
정수를 반환해요.
주어진 랭크가 유효하지 않으면(1부터 8 사이가 아니면) 0(0)을 반환해요.
CountInRank(board, 2)
// => 1
CountAll(board Chessboard) int 함수를 구현해요.
체스판에 칸이 몇 개 있는지 세어 정수를 반환해요.
칸의 내용은 확인할 필요가 없으니, index와 value를 모두 생략하는 range를 사용해 보세요.
CountAll(board)
// => 64
CountOccupied(board Chessboard) int 함수를 구현해요.
체스판에서 점유된 칸의 개수를 세요.
정수를 반환해요.
CountOccupied(board)
// => 15
Exercism에 가입하고 Go 트랙을 개념 34개연습 문제 166개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.