11. 구조체
11. 구조체
✅ 1. 구조체 선언
1
2
3
4
5
6
type Student struct {
Name string
Class int
No int
Score float64
}
type
키워드로 사용자 정의 타입임을 정의한다- 타입명의 첫 번째 글자가 대문자면 패키지 외부로 공개되는 타입이다
- 타입 종류인
struct
를 적는다
✅ 2. 구조체 변수 초기화
2.1 초깃값 생략
- 초깃값을 생략하면 모든 필드가 기본값으로 초기화된다
1
var house House
2.2 모든 필드 초기화
- 모든 필드값을 중괄호 사이에 넣어 초기화한다
모든 필드가 순서대로 초기화된다
1 2 3 4 5 6 7 8
var house House = House{"관악구", 27, 9.0, "아파트"} var house House = House{ "관악구", 27, 9.0, "아파트", // 여러 줄 초기화 시 마지막 값 뒤에 쉼표를 달아야 한다 }
2.3 일부 필드 초기화
일부 필드만 초기화하는 경우
필드명: 필드값
형식으로 초기화한다. 나머지 변수는 기본값으로 초기화된다1 2 3 4 5 6
var b Student = Student{no: 1, Class: 2} var c Student = Student{ no: 1, Class:2, }
✅ 3. 구조체를 포함하는 구조체
1
2
3
4
5
6
7
8
9
10
11
12
13
14
type VIPUser struct {
UserInfo User
Level int
}
func main() {
vip := VIPUser {
User{1, "Nam", 2},
3,
}
fmt.Printf("Id: %d\nName: %s\n",
vip.UserInfo.Id, vip.Name}
// vip.Name undefined (type VIPUser has no field or method)
- 구조체 내에 구조체 변수를 포함하는 경우, 내부 구조체 변수에 접근하려면
vip.UserInfo.Name
형식으로 접근해야 한다
3.1 포함된 필드 방식
- 위 방식처럼 접근하지 않고 구조체 내 구조체의 필드에 직접 접근하고 싶다면 구조체 필드명을 생략해야한다
- 단, 필드명이 중복일 경우 외부 구조체 필드에 먼저 접근하므로, 내부 구조체 필드에 접근하기 위해서는
vip.User.Level
과 같이 구조체명을 쓴 후 접근해야한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type VIPUser struct {
User
Level int
}
func main() {
vip := VIPUser {
User{1, "Nam", 2},
3,
}
fmt.Printf("Id: %d\nName: %s\nVIP Level: %v\nLevel: %v\n",
vip.Id, vip.Name, vip.User.Level, vip.Level)
// 내부 구조체의 필드는 vip.User.Level로 접근 가능
✅ 4. 구조체 값 복사
- 구조체 변수를 다른 구조체에 대입하면 모든 필드값이 복사된다
- Go 내부에서는 필드 각각이 아닌 구조체 전체를 복사한다
✅ 5. 구조체 크기
5.1 메모리 정렬
- 컴퓨터가 데이터에 효과적으로 접근하고자 메모리를 일정 크기 간격으로 정렬하는 것
- 레지스터 크기가 8바이트인 64비트 컴퓨터는 한 번에 8바이트 크기를 연산할 수 있다.
- 따라서 데이터가 레지스터 크기와 동일한 크기로 정렬되어 있으면 더욱 효율적으로 데이터를 읽어올 수 있다.
- 4바이트 필드, 8바이트 필드가 있는 구조체 변수가 메모리에 저장되는 경우, 4바이트 필드와 8바이트 필드 사이에 4바이트의 공간이 생기는데, 이를 메모리 패딩이라고 한다
5.2 메모리 패딩을 고려한 필드 배치
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type User1 struct {
A int8
B int64
C int8
D int64
E int8
}
type User2 struct {
A int8
C int8
E int8
B int64
D int64
}
func main() {
user1 := new(User1)
user2 := new(User2)
fmt.Println(unsafe.Sizeof(*user1)) // 40
fmt.Println(unsafe.Sizeof(*user2)) // 24
}
- User1
- 1바이트 필드 A를 저장한 후 8바이트 필드 B를 저장할 때 7바이트 x 3만큼의 메모리 패딩이 발생한다
OXXXXXXX | OOOOOOOO | OXXXXXXX | OOOOOOOO | OXXXXXXX
→ 40바이트
- User2
- 1바이트 필드 A, C, E를 몰아서 저장하여 5바이트만큼의 메모리 패딩이 발생한다
OOOXXXXX | OOOOOOOO | OOOOOOOO
→ 24바이트
This post is licensed under CC BY 4.0 by the author.