배열이란
배열은 같은 타입의 데이터들로 이루어진 타입이다.
- 배열을 이루는 각 값은 요소(element)이다.
- 요소를 가리키는 위치 값을 인덱스(index)라고 한다.
배열은 같은 타입의 여러 데이터를 하나의 변수로 효과적으로 사용할 수 있도록 해준다.
변수 선언 형식
var 변수명 [요소개수]타입
var t [5]float64
예제 1
package main
import "fmt"
func main() {
var t [5]float64 = [5]float64{24.0, 25.9, 27.8, 26.9, 26.2} // ❶
for i := 0; i < 5; i++ { // ❷
fmt.Println(t[i]) // ❸
}
}
---
24
25.9
27.8
26.9
26.2
배열 사용법
1️⃣ 배열 변수 선언 및 초기화
- int 타입
- int 타입 요소를 5개 갖는 배열 nums를 할당한다.
- 초깃값을 지정하지 않아 각 요솟값은 int 타입의 기본값인 0으로 초기화 된다.
var nums [5]int
- string 타입
- string 타입 요소 3개를 갖는 배열 day를 할당한다.
days := [3]string{"monday", "tuesday", "wednesday"}
- float64 타입
- float64 타입 요소를 5개 갖는 배열 temps를 할당한다.
- 첫 번째 두 번째 element는 각각 24.3과 26.7로 초기화 된다.
- 나머지는 float64의 기본값인 0.0으로 초기화된다.
var temps [5]float64 = [5]float64{24.3, 26.7}
- int 타입
- int 타입 요소를 갖는 배열 s를 할당한다.
- 인덱스가 1인 element를 10으로, 3인 element를 30으로 초기화한다.
- 나머지는 int타입의 기본값인 0으로 초기화된다.
var s = [5]int{1:10, 3:30}
- 배열 요소 개수 생략
- … 를 사용하여 배열 요소 개수를 생략할 수 있다.
- 배열 요소 개수는 초기화되는 요소의 개수와 같다.
- 초기화 개수가 3개이므로 x의 요소는 3개가 되고 각각 10, 20, 30으로 초기화됨.
- … 를 사용하여 배열 요소 개수를 생략할 수 있다.
x := [...]int{10, 20, 30}
2️⃣ 배열 선언 시 개수는 항상 상수
배열 선언 시 개수는 항상 상수로 써야 한다.
- 즉, 변숫값을 배열 개수로 사용하지 못함
예제
package main
const Y int = 3 // ❶ 상수
func main() {
x := 5 // ❷ 변수
a := [x]int{1, 2, 3, 4, 5} // ❸
b := [Y]int{1, 2, 3} // ➍
var c [10]int // ➎
}
- ❸에서 에러가 발생한다.
- 변수로 선언한 x를 배열 길이로 사용하지 못한다.
3️⃣ 배열 요소 읽고 쓰기
배열 요소에 접근하고 값을 읽고 쓰려면 배열 변수에 대괄호 [ ]를 쓰고 그 사이에 접근하고자 하는 요소의 인덱스를 적는다.
예제
package main
import "fmt"
func main() {
nums := [...]int{10, 20, 30, 40, 50} // ❶
nums[2] = 300 // ❷
for i := 0; i < len(nums); i++ { // ❸
fmt.Println(nums[i]) // ➍
}
}
4️⃣ range 순회
for 반복문에서 range 키워드를 이용하면 배열 요소를 순회할 수 있다.
package main
import "fmt"
func main() {
var t [5]float64 = [5]float64{24.0, 25.9, 27.8, 26.9, 26.2} // ❶
for i, v := range t { // ❷
fmt.Println(i, v) // ❸
}
}
---
0 24
1 25.9
2 27.8
3 26.9
4 26.2
- ❷ range를 사용해 모든 배열 요소를 순회한다.
- for문에서 i는 인덱스이고 v는 원솟값이다.
만약 인덱스가 필요 없고 요솟값만 필요하면 밑줄 _ 을 이용하여 인덱스를 무효화할 수 있다.
for _, v := range t {
fmt.Println(v)
}
}
💡 range 순회는 배열뿐만 아니라 문자열, 슬라이스, 맵, 채널 등에도 사용할 수 있다.
배열 is 연속된 메모리
- 배열을 선언하면 컴퓨터에서는 연속된 메모리 공간을 확보한다.
- ex) var a [10]int32 배열 선언 시 int32값 10개를 저장할 수 있는 연속된 메모리 공간을 찾아 할당함.
- int32 타입은 4바이트이므로 연속된 40바이트를 찾아 할당한다.
- ex) var a [10]int32 배열 선언 시 int32값 10개를 저장할 수 있는 연속된 메모리 공간을 찾아 할당함.
- 인덱스 요소를 찾아가는 방법은 배열의 시작 주소에 인덱스 * 타입 크기를 더해서 찾아간다.
요소 위치 = 배열 시작 주소 + (인덱스 * 타입 크기)
배열의 핵심
- 배열은 연속된 메모리이다.
- 컴퓨터는 인덱스 타입 크기를 사용하여 메모리 주소를 찾는다.
배열 복사
대입 연산자를 사용하여 배열 대 배열을 복사할 수 있다.
예제
package main
import "fmt"
func main() {
a := [5]int{1, 2, 3, 4, 5}
b := [5]int{500, 400, 300, 200, 100}
for i, v := range a { // ❶ 배열 a 원소 출력
fmt.Printf("a[%d] = %d\\n", i, v)
}
fmt.Println() // ❷ 개행
for i, v := range b { // ❸ 배열 b 원소 출력
fmt.Printf("b[%d] = %d\\n", i, v)
}
b = a // ❹ a 배열을 b변수에 복사
fmt.Println() // 개행
for i, v := range b { // ➎ 배열 b 원소 출력
fmt.Printf("b[%d] = %d\\n", i, v)
}
}
- Go언어에서 대입 연산자는 우변의 값을 좌변의 메모리 공간에 복사한다.
- 복사되는 크기는 타입의 크기와 같다.
- b = a
- a타입, b타입은 int 타입으로 요소당 8바이트씩, 총 40바이트이다.
- a의 값은 변수 a가 가리키는 메모리 공간의 값, 즉 배열 전체를 뜻한다.
- 그래서 Go언어에서 배열 간 대입은 전체 배열의 복사로 동작한다.
그러나 아래처럼 복사하려는 배열의 타입이 다르면 에러가 발생한다.
a := [5]int{1, 2, 3, 4, 5}
b := [5]float32{500, 400, 300, 200, 100}
b = a // error
- Go언어에서 모든 연산자의 각 항의 타입은 항상 같아야 한다. 대입 연산자도 마찬가지이다.
다중 배열
배열은 이중 배열, 삼중 배열처럼 여러 번 중첩해서 사용 가능하다. 이를 다중 배열이라고 한다.
- 이중 배열은 X, Y 좌표계의 위치 데이터들을 위해 주로 사용되어 이차원 배열이라고 부른다.
- 삼중 배열은 삼차원 공간상의 좌표 데이터들을 위해 주로 사용되어 삼차원 배열이라고 부른다.
간단하게 다중 배열은 배열을 요소로 가지는 배열이라고 이해하면 쉽다.
초깃값 선언
배열에 초깃값을 넣는데 { } 를 사용한다. 이중 배열은 어떻게 할까?
var b = [2][5]int{
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
}
⚠️ } (닫는 중괄호) 가 마지막 요소와 같은 줄에 있지 않으면 마지막 항목 뒤에 , 를 찍어줘야 한다.
예제
package main
import "fmt"
func main() {
a := [2][5]int{ // ❶ 이중 배열 선언
{1, 2, 3, 4, 5},
{5, 6, 7, 8, 9}, // ❷ 여러 줄에 걸쳐 초기화할 때는 쉼표를 찍자!
}
for _, arr := range a { // ❸ arr값은 순서대로 a[0]의 배열 a[1]의 배열
for _, v := range arr { // ❹ v값은 순서대로 a[0]과 a[1] 배열의 각 원소
fmt.Print(v, " ") // ➎ v값 출력
}
fmt.Println()
}
}
- ❸ range 를 이용하여 a 배열 요소들을 순회한다.
- 첫 번째 반복때는 a[0]
- 두 번째 반복때는 a[1]
- ❹ range를 이용하여 arr 배열 요소들을 순회한다.
- 첫 번째 반복때는 a[0]의 모든 요소
- 두 번째 반복때는 a[1]의 모든 요소
배열 크기
위에서 배열은 연속된 메모리 공간이라고 하였고 메모리 크기는 선언된 타입에 의해 결정된다고 했다.
그래서 배열 크기는 타입 크기 요소 개수가 된다.
배열 크기 = 타입 크기 * 항목 개수
- [2][5]int의 이중 배열의 메모리 크기는 [5]int는 40바이트니까 2를 곱한 값인 80바이트이다.
- 삼중도 마찬가지..
💡 배열을 이중, 삼중으로 선언하는 것은 프로그래머가 다루기 편함이다.
컴퓨터 입장에서는 [3][2][5]int나 [30]int이나 처리 하는 방법은 동일하다!
(단, 배열 내 요소에 접근할 때 [0][1][3]과 같이 여러 차수로 접근할 수 있느냐 [8]과 같이 하나의 차수로 접근하냐가 다르다.)
핵심 요약
- 배열은 값을 여러 개 저장하는 연속된 메모리 공간이다.
- 대괄호 [ ] 사이에 인덱스를 넣어서 배열 요소에 접근할 수 있다. a[3]은 a 배열에서 인덱스가 3인 요소에 접근한다.
- 배열의 인덱스는 0부터 시작한다.
- 내장 함수 len()으로 배열 길이를 알 수 있다.
- range를 이용하면 for문에서 배열을 순회할 수 있습니다.
'Programming > Go' 카테고리의 다른 글
[Golang] 포인터 (Pointer) (0) | 2022.11.13 |
---|---|
[Golang] 구조체 (Structure) (1) | 2022.11.13 |
[Golang] for문 (0) | 2022.11.11 |
[Golang] Switch문 (0) | 2022.11.06 |
[Golang] if문 (0) | 2022.11.06 |