Tucker의 Go 언어 프로그래밍 책과 유튜브를 통해 학습 중입니다.
배열
- 같은 타입의 데이터들로 이루어진 타입(Type)
- 배열을 이루는 각 값은 요소라고 하고, 요소(Element)를 가르키는 위치 값을 인덱스(Index)라고 함
- 배열의 인덱스는 0부터 시작하며 마지막은 '갯수 -1'
- 같은 타입의 여러 데이터를 하나의 변수로 효과적으로 사용할 수 있음
- 배열은 자료구조 중 한 종료임
var 변수명 [요소 개수]타입
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
var t [5]float64 = [5]float64{24.0, 25.9, 27.8, 26.9, 26.2}
- 앞[5]float64는 공간, 뒤 [5]float64는 값이며, =는 초기화, t라는 변수에 뒤에 변수를 복사하는 것
for i := 0; i < 5; i++ {
- 배열을 순회할 때 for문을 많이 사용함
→ 결과 값은 t[0], t[1], t[2], t[3], t[4]이 출력됨
→ 인덱스는 0부터 시작하기 때문에 t[0]이 첫 번째 값
다양한 배열 변수 선언
var temps [5]float64 = [5]float64{24.3, 26.7}
temps[0] | temps[1] | temps[2] | temps[3] | temps[4] |
24.3 | 26.7 | 0 | 0 | 0 |
- 5개를 갖는 배열이지만, 첫 번째와 두 번째는 지정한 값이 나머지 빈칸은 float64의 기본 값인 0.0으로 초기화 됨
var s =[5]int{1:10, 3:30}
s[0] | s[1] | s[2] | s[3] | s[4] |
0 | 10 | 0 | 30 | 0 |
- s의 타입은 뒤의 값과 동일함
- 1:10 은 인덱스 1에 해당하는 자리에 10을 넣고, 3:30은 인덱스 3에 30을 넣는 것 = 특정 인덱스 값을 지정할 수 있음
x := [...]int{10, 20, 30}
x[0] | x[1] | x[2] |
10 | 20 | 30 |
- [...]은 int 값(초기값)의 길이로 정하겠다는 의미로, 3개의 배열이 됨 = [3]int -> 길이가 늘지도 줄지도 않고 3개 고정
- 주의 할 점은 []만 사용해서 배열을 만들 경우 타입이 달라짐 -> 동적 배열(slice)로 길이가 늘어날 수 있는 배열임
배열 선언 시 개수는 항상 상수
- 배열 선언시 [n]int의 n은 항상 상수 값만 사용할 수 있음
- 변숫값을 배열 개수로 사용할 수 없음(변수의 값이 바뀌어 길이 값이 변할 수 있기 때문, 고정되어있어야 프로그램이 메모리를 얼마나 할당할지 알 수 있음)
- 상수를 길이로 사용할 수 있음(길이 값이 변하지 않음)
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
}
// 결과
Error!!!
배열 순회
- Go뿐만 아니라 다른 언어에서도 아래처럼 사용함
package main
import "fmt"
func main() {
nums := [...]int{10, 20, 30, 40, 50} // [5]int{10, 20, 30, 40, 50}과 동일
nums[2] = 300
for i := 0; i < len(nums); i++ {
fmt.Println(nums[i])
}
}
// 결과
10
20
300
40
50
- len() 내장함수로, 뒤에 배열이나 다른 값이 들어오는 경우 길이를 반환함
→ 위에 int의 값이 변해 배열 개수가 변할 수 있기 때문에 사용(편함)
range 순회
- Go에서 제공하는 방법
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는 키워드로 range 다음의 타입은 자료구조, 슬라이스, 스트링, 맵 등의 요소들을 돌아가면서 순회하면서 값을 2개를 반환함.
- 배열은 첫 번째 값에 인덱스(해당 하는 값의 인덱스 반환), 두 번째는 요소값을 출력하고 모든 값을 다 순회하면 for문이 끝남.
→ 만약 출력을 fmt.Println(v)만 하게 되면 Go에서는 컴파일 에러가 발생 = 변수를 선언하고 사용하지 않아서
→ 첫 번째 값을 사용하지 않고 싶은 경우 _(빈칸 지시자)을 사용하여 자리만 표시할 수 있음(인덱스 무효화)
배열은 연속된 메모리
- 배열은 연속된 메모리로, 배열 선언 시 컴퓨터는 연속된 메모리 공간을 확보함.
var a [10]int32
- 변수의 타입은 메모리 크기를 의미함 (Type데이터 형태도 의미하지만 크기도 의미함)
- [10]int32는 4bybe정수 요소로, 4byte가 10개 = 40byte 자리를 한 번에 (연속적으로)할당하여 각 요소 값을 채워 넣음
- 컴퓨터는 배열의 시작주소는 (메모리 시작 주소) + (인덱스 * 타입 크기=요소)로 자리를 찾아감
- 배열은 요소를 찾아가는 속도가 매우 빠름
* 배열의 핵심
1️⃣ 배열은 연속된 메모리
2️⃣ 컴퓨터는 인덱스와 타입 크기를 사용해서 (간단하게)메모리 주소를 찾음
배열 복사
- 대입 연산자를 사용하면 배열 대 배열을 복사할 수 있음
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 {
fmt.Printf("a[%d] = %d\n", i, v)
}
fmt.Println()
for i, v := range b {
fmt.Printf("b[%d] = %d\n", i, v)
}
b = a
fmt.Println()
for i, v := range b {
fmt.Printf("b[%d] = %d\n", i, v)
}
}
// 결과 값
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
b[0] = 500
b[1] = 400
b[2] = 300
b[3] = 200
b[4] = 100
b[0] = 1
b[1] = 2
b[2] = 3
b[3] = 4
b[4] = 5
- =(대입연산자)가 실행되면 값을 복사하는데 우변의 값 타입의 크기만큼 복사함
- Golang 에서는 항상 공간의 크기가 같아야 함(양변의 크키가 다르면 복사할 수가 없음)
다중 배열
- 다중 배열은 중첩된 배열을 의미
- 이중, 삼중 배열처럼 여러 번 증첩해서 사용할 수 있음
- 이중 배열은 X, Y 좌표계의 위치 데이터들을 위해 주로 사용되어 이차원 배열이라고 부름
- 삼중 배열은 삼차원 공간상의 좌표 데이터들을 위해 주로 사용되어서 삼차원 배열이라고 부름
→ 컴퓨터는 차원 형태로 데이터를 저장하지 않고 차원에 상관없이 전체 요소 개수만큼 연속된 메모리 형태로 저장
var b [2][5]int
→ [5]int가 두 개인 배열로 b[0]은 첫 번째 [5]int 배열이 되고, b[1]은 두 번째 [5]int 배열이 됨
- 배열은 몇 개가 중첩되었던 [개수] 타입 형태
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()
}
}
// 출력
1 2 3 4 5
5 6 7 8 9
a := [2][5]int{
→ [2][5]int로 이중 배열 a를 선언하고 초기화
→ a[0]은 첫 번째 [5]int 배열이고, a[1]은 두 번째 [5]int 배열이 됨
{1, 2, 3, 4, 5},
→ a[0] 초기화용 {}
{5, 6, 7, 8, 9},
→ a[1] 초기화용 {}
→ Go에서는 중괄호가 열리고 닫힐 때 요소들이 같은 줄에서 닫히면 콤마가 필요 없지만 다른 줄에서 닫히면 ,(콤마)를 찍어줘야 함
for _, arr := range a {
→ arr은 5개짜리 int 타입의 배열
* 쉼표(,)
→ Go에서는 중괄호가 열리고 닫힐 때 요소들이 같은 줄에서 닫히면 콤마가 필요 없지만 다른 줄에서 닫히면 ,(콤마)를 찍어줘야 함
a := [2][5]int{ {1, 2, 3, 4, 5}, {5, 6, 7, 8, 9} } // 쉼표 없음
a := [2][5]int {
{1, 2, 3, 4, 5},
{5, 6, 7, 8, 9} } // 쉼표 없음
→ 닫는 중괄호가 마지막 항목과 같은 줄에 있을 때 쉼표를 찍지 않음
a := [2][5]int {
{1, 2, 3, 4, 5},
{5, 6, 7, 8, 9}, // 쉼표 찍어 줘야함
}
→ 닫는 중괄호가 마지막 항목과 같은 줄에 있지 않기 때문에 쉼표를 찍어야 함
a := [2][5]int {
{1, 2, 3, 4, 5}, // 닫는 중괄호가 같은 줄에 있지 않아서 쉼표
{5, 6, 7, 8, 9, // 닫는 중괄호가 같은 줄에 있어서 쉼표 없음
} }
배열 크기
- 배열이 선언되면 컴퓨터는 배열의 모든 요소를 저장할 수 있게 청크 형태로 연속적인 메모리가 할당 됨
- 배열 크기 = 타입 크기 * 항목 개수
- 배열을 이중, 삼중으로 선언하는 건 사람이 다루기 편하기 위함이지 컴퓨터 입장에서는 메모리 크기만 중요함
→ 컴퓨터 입장에서는 [3][2][5]int나 [30]int나 처리하는 방법은 동일함.
→ 단, 배열 내 항목을 접근할 때 [0][1][3]과 같이 여러 차수로 접근할 수 있느냐 [8]과 같이 하나의 차수로 접근하느냐의 차이
✓ [2][5]int의 이중 배열 크기는 [2]([5]int)라고 볼 수 있음 즉, [5]int 배열이 2개 있는 배열로 [5]int의 크기는 40바이트이니, [2][5]int 크기는 80(40 x 2)바이트가 됨. (int타입의 크기는 8바이트)
'Language > Golang' 카테고리의 다른 글
Golang (Go언어) 포인터(Pointer) (3) | 2024.11.07 |
---|---|
Golang (Go언어) 구조체(Structure) (9) | 2024.11.05 |
Golang (Go언어) for문 (반복문) (4) | 2024.10.31 |
Golang (Go언어) Switch문 (조건문) (4) | 2024.10.31 |
Golang (Go언어) IF문 (조건문) (4) | 2024.10.30 |