소개
이전 섹션에서 배열의 기본 사용법에 대해 배웠습니다.
배열에는 어떤 유형의 요소가 들어갈 수 있을까요?
Go 에서 배열의 요소는 정수, 문자열 또는 사용자 정의 유형과 같은 모든 기본 유형일 수 있습니다.
배열의 요소가 배열인 경우 어떻게 될까요?
그러면 다차원 배열이 됩니다.

위 그림과 같이 보라색 상자가 원래 배열입니다.
보라색 상자 배열의 각 요소는 새로운 배열 (빨간색 상자) 입니다.
핵심 개념:
- 2 차원 배열의 정의
- 2 차원 배열의 초기화
- 2 차원 배열 순회 (Traversing)
- 다차원 배열의 사용
2 차원 배열 정의
일반적인 정의
일반 배열을 정의하는 방법을 기억하시나요?
var variableName [elementCount]variableType
그렇다면 이 가장 기본적인 방법으로 2 차원 배열을 어떻게 정의할까요?
var variableName [elementCount][elementCount]variableType
유일한 차이점은 원래 [elementCount] 앞에 다른 [elementCount]를 추가하여 [elementCount][elementCount] 형식을 형성한다는 것입니다.
예를 들어, int 타입의 10*10 용량을 가진 a라는 2 차원 배열을 정의하려면 다음 구문을 사용할 수 있습니다.
var a [10][10]int
간결한 정의
짧은 변수 선언과 마찬가지로, 간결한 정의 방법을 사용하여 배열, 심지어 다차원 배열도 선언할 수 있습니다.
:=를 사용하여 다차원 배열을 포함한 배열을 선언할 수 있습니다.
예를 들어:
a := [10][10]int{}
이 방법으로 크기가 10*10인 정수 2 차원 배열을 정의합니다.
2 차원 배열 초기화
1 차원 배열과 유사하게, 2 차원 배열을 다음과 같은 방법으로 초기화할 수 있습니다.
- 초기화 목록 (Initialization list)
- 길이 추론 초기화 (Inferred length initialization)
- 지정된 인덱스 값 초기화 (Specified index value initialization)
이러한 방법을 어떻게 사용하는지 기억하시나요?
이전 섹션에서 1 차원 배열에서 이러한 방법을 사용하는 방법을 배웠습니다. 잊어버렸더라도 괜찮습니다.
다음 섹션에서는 이 세 가지 초기화 방법을 검토하고 이를 2 차원 배열로 확장합니다.
초기화 목록을 사용한 2 차원 배열 초기화
이전 섹션에서 생성한 array.go 파일을 계속 사용해 보겠습니다. 작업을 저장하지 않았다면 다음과 같이 파일을 생성할 수 있습니다.
touch ~/project/array.go
array.go에 다음 코드를 작성합니다.
package main
import "fmt"
func main() {
// 자동으로 0 으로 초기화
var simpleArray [3][3]int
// 지정된 초기 값을 사용하여 초기화, 누락된 요소에 대한 기본값 사용
var numArray = [3][3]int{{1, 2, 3}, {2, 3, 4}}
// 지정된 초기 값을 사용하여 초기화
var cityArray = [2][2]string{{"London", "Chengdu"}, {"Paris", "Boston"}}
fmt.Println(simpleArray) // [[0 0 0] [0 0 0] [0 0 0]]
fmt.Println(numArray) // [[1 2 3] [2 3 4] [0 0 0]]
fmt.Println(cityArray) // [[London Chengdu] [Paris Boston]]
}
위 코드는 초기화 목록을 사용하여 2 차원 배열을 초기화하는 세 가지 방법을 보여줍니다.
다음 명령을 사용하여 코드를 실행합니다.
go run ~/project/array.go
출력 결과는 다음과 같습니다.
[[0 0 0] [0 0 0] [0 0 0]]
[[1 2 3] [2 3 4] [0 0 0]]
[[London Chengdu] [Paris Boston]]
값을 수정하고 1 차원 배열에 대한 초기화 방법을 검토할 수 있습니다.
추론된 길이를 사용한 2 차원 배열 초기화
2 차원 배열에서 1 차원 배열에서 했던 것처럼 길이 추론 (inferred length) 방법을 사용하여 초기화할 수 있습니다.
array.go에 다음 코드를 작성합니다.
package main
import "fmt"
func main() {
// 자동으로 0 으로 초기화
var simpleArray [3][3]int
// 지정된 초기 값을 사용하여 초기화, 누락된 요소에 대한 기본값 사용
var numArray = [...][]int{{1, 2, 3, 3}, {2, 3, 4, 3}, {0}}
// 지정된 초기 값을 사용하여 초기화
var cityArray = [...][2]string{{"London", "Chengdu"}, {"Paris", "Boston"}}
fmt.Println(simpleArray) // [[0 0 0] [0 0 0] [0 0 0]]
fmt.Println(numArray) // [[1 2 3 3] [2 3 4 3] [0]]
fmt.Println(cityArray) // [[London Chengdu] [Paris Boston]]
}
위 코드는 길이 추론을 사용하여 2 차원 배열을 초기화하는 것을 보여줍니다.
go run ~/project/array.go
출력 결과는 초기화 목록 (initialization list) 방법과 동일합니다.
[[0 0 0] [0 0 0] [0 0 0]]
[[1 2 3 3] [2 3 4 3] [0]]
[[London Chengdu] [Paris Boston]]
그러나 1 차원 배열과 달리, 2 차원 배열의 길이 추론 초기화에서 ... 기호는 첫 번째 대괄호 안에만 존재할 수 있습니다.
예를 들어:
var numArray = [...][]int{{1, 2, 3, 3}, {2, 3, 4, 3}}
이 코드는 유효하지만, 다음 두 가지 변형은 잘못되었습니다.
var numArray = [][...]int{{1, 2, 3, 3}, {2, 3, 4, 3}}
var numArray = [...][...]int{{1, 2, 3, 3}, {2, 3, 4, 3}}
또한 numArray와 cityArray를 비교해 보겠습니다.
cityArray에서 2 차원 배열의 크기의 두 번째 매개변수를 지정하는 것을 볼 수 있습니다. 아래와 같습니다.
var cityArray = [...][2]string{{"London", "Chengdu"}, {"Paris", "Boston"}}
이는 초기화 중에 각 하위 배열의 크기를 2로 지정한다는 의미입니다.
초기화 중에 주어진 값이 충분하지 않으면, 데이터 유형의 기본값이 누락된 요소를 채우는 데 사용됩니다.
주어진 값의 수가 지정된 크기를 초과하면 오류가 발생합니다.
지정된 인덱스 값을 사용한 2 차원 배열 초기화
1 차원 배열과 유사하게, 2 차원 배열에서도 지정된 인덱스 값 (index value) 을 사용하여 초기화할 수 있습니다. 과정은 유사합니다.
array.go에 다음 코드를 작성합니다.
package main
import "fmt"
func main() {
a := [...][]int{1: {1, 2, 3}, 3: {4, 7, 9}}
fmt.Println(a) // [[] [1 2 3] [] [4 7 9]]
fmt.Printf("Type of array a: %T\n", a) // Type of array a: [4][]int
}
go run ~/project/array.go
출력 결과는 다음과 같습니다.
[[] [1 2 3] [] [4 7 9]]
Type of array a: [4][]int
위 코드는 배열 a를 결정되지 않은 길이 (indeterminate length) 를 가진 2 차원 배열로 정의합니다. 인덱스 1에 값 [1 2 3]을 할당하고, 인덱스 3에 값 [4 7 9]를 할당합니다.
자동으로 추론된 길이의 경우, 배열 a의 타입은 [4][]int입니다.
2 차원 배열 순회
2 차원 배열을 어떻게 순회할까요?
1 차원 배열을 배울 때, 배열을 순회하는 두 가지 방법, 즉 range 키워드 사용과 인덱스 번호 (index number) 사용을 배웠습니다.
이제 이 두 가지 방법을 2 차원 배열을 순회하는 데 적용해 보겠습니다.
array.go에 다음 코드를 작성합니다.
package main
import "fmt"
func main() {
a := [...][]int{{123, 321, 222}, {404, 501, 503}, {857, 419, 857}}
// Method 1: using the range keyword
fmt.Println("Traversing the Two-Dimensional Array Using the range Keyword")
for index, value := range a {
for i, j := range value {
fmt.Println(index, i, j)
}
}
// Method 2: using index numbers
fmt.Println("\nTraversing the Two-Dimensional Array Using Index Numbers")
for i := 0; i < len(a); i++ {
for j := 0; j < len(a[i]); j++ {
fmt.Println(i, j, a[i][j])
}
}
}
위 코드는 2 차원 배열을 순회하는 두 가지 방법을 보여줍니다.
go run ~/project/array.go
출력 결과는 다음과 같습니다.
Traversing the Two-Dimensional Array Using the range Keyword
0 0 123
0 1 321
0 2 222
1 0 404
1 1 501
1 2 503
2 0 857
2 1 419
2 2 857
Traversing the Two-Dimensional Array Using Index Numbers
0 0 123
0 1 321
0 2 222
1 0 404
1 1 501
1 2 503
2 0 857
2 1 419
2 2 857
두 방법 모두 동일한 결과를 생성하지만, 근본적으로 다릅니다. 이러한 차이점은 실제로 배열을 사용할 때 특히 명확해질 것입니다.
배열의 실용적인 사용
이전 섹션에서, 배열 순회 (array traversal) 의 두 가지 방법이 근본적으로 다르다고 언급했습니다.
이것을 설명하기 위해 작은 예제를 사용해 보겠습니다.
array.go에 다음 코드를 작성합니다.
package main
import "fmt"
func main() {
a := [...][]int{{123, 321, 222}, {404, 501, 503}, {857, 419, 857}}
// Method 1: using the range keyword
fmt.Println("Traversing the Two-Dimensional Array Using the range Keyword")
for _, value := range a {
for _, j := range value {
fmt.Println(j)
}
}
fmt.Println(a)
// Method 2: using index numbers
fmt.Println("\nTraversing the Two-Dimensional Array Using Index Numbers")
for i := 0; i < len(a); i++ {
for j := 0; j < len(a[i]); j++ {
fmt.Println(a[i][j])
a[i][j] = 0
}
}
fmt.Println(a)
}
위 코드는 두 가지 다른 방법을 사용하여 2 차원 배열의 모든 값을 0으로 설정하는 것을 보여줍니다.
go run ~/project/array.go
프로그램 출력 결과는 다음과 같습니다.
Traversing the Two-Dimensional Array Using the range Keyword
123
321
222
404
501
503
857
419
857
[[123 321 222] [404 501 503] [857 419 857]]
Traversing the Two-Dimensional Array Using Index Numbers
123
321
222
404
501
503
857
419
857
[[0 0 0] [0 0 0] [0 0 0]]
range 키워드를 사용하여 배열을 순회할 때, 값을 수정해도 아무런 효과가 없다는 것을 알 수 있습니다. 그러나 인덱스 번호를 사용하여 배열을 순회한 후에는 값을 수정하는 것이 효과적입니다. 이는 range 키워드를 사용하여 배열을 순회할 때, 루프 변수 j가 실제로 배열 값의 **복사본 (copy)**이기 때문입니다. 복사본의 값을 수정하는 것은 원래 배열 a에 영향을 미치지 않습니다. 그러나 인덱스 번호를 사용하여 배열을 순회할 때는 원래 배열의 값을 수정하는 것이 유효합니다.
2 차원 배열의 업스케일링
때로는 3 차원 배열 또는 4 차원 배열을 사용해야 할 필요가 있습니다.
더 높은 차원의 배열로 확장하는 것은 1 차원 배열을 2 차원 배열로 확장하는 것과 크게 다르지 않습니다.
간단한 예제를 살펴보겠습니다.
package main
import "fmt"
func main() {
a := [2][2][2]int{}
for i := 0; i < 2; i++ {
for j := 0; j < 2; j++ {
for k := 0; k < 2; k++ {
a[i][j][k] = 1
}
}
}
fmt.Println(a)
}
위 코드는 3 차원 배열을 정의하고 사용하는 방법을 보여줍니다. 4 차원 또는 더 높은 차원의 배열도 동일한 과정을 거칩니다.
go run ~/project/array.go
출력 결과는 다음과 같습니다.
[[[1 1] [1 1]] [[1 1] [1 1]]]
하지만, 더 높은 차원의 배열은 일반적으로 사용되지 않습니다. 따라서 개념을 이해하는 것으로 충분합니다.
요약
이 랩 (lab) 에서 우리는 다음을 배웠습니다.
- 2 차원 배열을 정의하는 두 가지 방법
- 2 차원 배열을 초기화하는 세 가지 방법
- 2 차원 배열을 순회하는 두 가지 방법
- 실제 사용에서 두 가지 순회 방법의 차이점
- 다차원 배열 사용에 대한 개요



