2.5 사용하지 않는 변수
- 지역 변수는 반드시 사용되어야 함
- 사용되지 않는 상수는 허용
2.6 변수와 상수 이름 짓기
* Go는 유니코드 문자를 식별자로 허용
* Go는 관용적으로 스네이크 표기법 사용하지 않음
* 상수: 모든 문자를 대문자, 각 단어는 밑줄로 구분
- Go는 이러한 일반 상수 이름 규칙을 따르지 않는다
- 패키지에 포함된 요소를 외부에 노출시킬지(expose) 여부를 식별자의 첫글자가 대소문자 여부로 결정
* 함수 내에서는 짧은 변수 이름 선호
* 짧은 이름
* 패키지 블록 내
chap. 03 복합타입
3.1 배열(array)
* 같은 타입의 여러 데이터를 담음
* 시퀀스 타입 (순서 중요)
* Go에서는 선호하지 않음(특별한 경우에만 사용)
* 선언 시 크기를 지정해야 함
* 크기를 변경할 수 없다
* 선언 방법
1) 제로 값으로 선언: 배열의 크기와 배열 내 요소 타입 지정
2) 배열 초깃값 지정: 배열 리터럴 사용
3) 희소 배열: 대부분의 요소가 0인 배열
4) 배열 크기 지정하지 않고: 배열 리터럴 필요
5) 다차원 배열: []의 개수가 차원 수
* 배열 요소 접근
* 배열 길이
* Go에서 배열을 잘 사용하지 않는 이유
- 배열의 크기가 배열의 타입을 결정하는데 사용되기 때문
- 즉, 원소의 타입이 같은 배열이라도 크기가 다르면 다른 타입
- 크기(길이)가 다르면 타입 변환도 불가능
3.2 슬라이스
- 일련의 값(시퀀스)을 저장하는 자료 구조
- 순서 중요
- 슬라이스의 크기는 타입의 일부가 아니다 (배열과의 큰 차이점)
- 슬라이스 간 비교는 불가 (배열과 다른 점)
* 슬라이스 선언 (슬라이스 크기를 지정하지 않음)
1) 슬라이스 초깃값 지정: 슬라이스 리터럴
2) 희소 슬라이스
3) 다차원 슬라이스
4) 제로 슬라이스: 슬라이스 리터럴 없이 선언만 하는 것
- 슬라이스의 제로 값은 **nil**
- nil : 값의 부재(absence of value) 상태
- nil은 타입이 없음
5) 비어있는 슬라이스: 슬라이스 리터럴에 초깃값이 없는 것
* 슬라이스의 길이
3.2.2 append
- 슬라이스에 새로운 요소 추가
- append의 결과를 할당하지 않으면 컴파일 에러
3.2.3 수용력(capacity)
- 예약된(미리 준비된) 연속적인(consecutive) 메모리 공간의 크기
- 길이와 수용력
- 수용력 >= 길이
- 요소가 추가되면 길이는 커지고 결국 수용력과 같아짐
- 길이과 수용력이 같은 상태에서 요소가 추가되면 Go 런타임이 더 큰 수용력을 가지는 **새로운** 슬라이스를 할당, 원본 슬라이스의 값들은 새 슬라이스에 복사됨, 추가된 값은 새 슬라이스에 append되고 이 새 슬라이스가 반환된다.
- 수용력이 1024 보다 작으면 2배 증가, 그렇지 않으면 25%씩 확장
- cap() vs. len()
3.2.4 make()
- 슬라이스에 저장될 요소 개수를 미리 알 수 있다면 make()를 사용해 효율적인 슬라이스 작업을 도모할 수 있다
- make로 생성한 슬라이스에 append를 사용할 땐 주의할 것
3.2.5 슬라이스 선언
- var data []int => nil
- var data = []int{} => nil(X)
* 슬라이스를 아래 방식 중 어떤 걸로 생성할 지 정리해 봅시다.(p.75)
3.2.6 슬라이싱의 슬라이싱
-
슬라이스 연산자(:)
- 슬라이스로부터 슬라이스 생성
-
슬라이스 연산자를 사용하면 복사본을 만들지 않고 메모리를 공유함
-
슬라이싱과 append를 함께 사용하면 혼란이 가중됨
-
하위 슬라이스의 수용력
= 원본 슬라이스의 수용력 - 하위 슬라이스 시작 오프셋
-
하위 슬라이스와 append를 아무 생각 없이 사용하면 혼란이 가중된다.
- 의도치 않은 값 변경이 발생
- 완전한 슬라이스 표현식(full slice expression)으로 해결
-
완전한 슬라이스 표현식
- 하위 슬라이스에 얼마나 많은 메모리를 공유할 것인지를 지정
- 슬라이스 연산때 콜론을 한 번 더 사용하여 세번째 인자에 원본 슬라이스에서 하위 슬라이스의 마지막 요소의 위치 지정
- 슬라이스 연산의 세 번째 인자의 값을 두 번째 인자의 값과 같도록 설정
3.2.7 배열을 슬라이스로 변환
- 배열에 슬라이스 연산 적용
- 메모리 공유 문제 존재
3.2.8 copy
- copy() 내장 함수
- copy의 첫 번째 인자는 슬라이스이어야 함
3.3 문자열과 룬 그리고 바이트
- 문자열은 룬으로 이루어진 것은 아니다.
- 문자열은 바이트의 시퀀스이다.
- 문자열의 길이는 바이트 수
- 문자열에 슬라이스 연산 사용 가능
- 문자열은 수정불가(immutable)이므로 슬라이스의 메모리 공유 문제가 없음
- 유니코드로 구성되므로 슬라이스를 했을 때 문자가 깨지는 우려가 있음
- 문자열은 바이트 슬라이스 또는 룬 슬라이스로 변환 가능
3.4 맵
- 순서 없는 데이터 처리 유용
- (Key, Value) Pair
[SYNTAX]
var 변수명 map[키타입]값타입
- 생성
1) nil 맵(제로 값 할당): map의 제로 값은 nil
- nil 맵은 길이 0
- nil 맵의 값을 읽으면 맵 값이 되는 타입의 제로 값
- nil 맵에 값을 쓰려고 하면 패닉 발생
2) 비어 있는 맵 리터럴: 비어 있는 맵 생성
- nil 맵과 다르다
- 길이는 0
- 비어 있는 맵 리터럴이 할당된 맵을 읽고 쓸 수 있다.
3) 값이 있는 맵 리터럴
- 키와 값을 콜론으로 구분
- 마지막 요소(키, 값)의 끝에 콤마(,)를 붙인다.
4) make() 함수로 생성
- 맵의 요소 개수를 안다면
- 길이는 0 (make()로 슬라이스 만드는 것과 다름)
- 초기 지정 개수 이상으로 커질 수 있다.
- 맵의 제로 값은 nil
- 맵은 비교 불가능, 단 nil과 같은지 다른지는 비교 가능
3.4.1 맵 읽고 쓰기
- := 연산자는 사용 불가
- 아직 설정되지 않은 키에 할당된 값을 읽으면 값 타입의 제로 값이 반환된다.
3.4.2 콤마 OK 관용구(idiom)
- 맵의 키에 대응되는 값이 없어도 제로 값이 리턴되지만
- 맵에 키가 존재하는지 확인할 필요가 있을 때 주로 사용하는 패턴
- 맵에 키가 없어서 제로 값이 반환되는 건지
- 실제로 키가 있는데 해당 값이 제로인 건지
3.4.3 맵 (요소) 삭제
- delete() 내장 함수 사용
- 키가 존재하지 않거나 nil 맵인 경우 아무것도 일어나지 않음
- delete() 함수는 반환값이 없음
3.4.4 맵을 셋(집합)으로 이용
- 집합(셋)
- Uniqueness, 순서 없음
- Go는 집합형을 직접 지원하지 않고 맵을 통해 간접적으로 지원
- 집합의 원소로 쓰고 싶은 타입을 맵의 키 타입으로
- 맵의 값을 불리언으로 설정
3.5 구조체
- 여러 데이터 타입을 한데 묶어서 다루고 싶을 때 사용
- struct 키워드, type 키워드
- 구조체는 사용자 정의 타입
- 따라서 바로 사용할 순 없고
- 1) 구조체 정의 -> 2) 구조체를 타입으로 하는 변수 선언
- 구조체 항목들은 콤마로 구분하지 않는다
- 구조체는 어떤 블록 레벨에서도 정의 가능
- 구조체의 제로 값
- 구조체를 구성하는 항목들의 제로 값
- 구조체 리터럴
- 첫 번째 방법
- 구조체 항목 값은 구조체 정의한 순서대로 나열
- 구조체 항목 값은 콤마로 구분하고 마지막 항목에서 콤마를 붙여야 함
- 두 번째 방법
- 맵 리터럴과 유사
- 순서 무관
- 생략할 경우 제로 값으로 설정
- 위 두 방법을 혼용할 수 없음
- 제로 구조체와 비어 있는 구조체는 차이점이 없다
- 구조체의 멤버(항목)을 접근할 때는 인덱싱이 아니라 점 표기법을 사용
3.5.1 익명 구조체
- 한 번만 사용할 구조체
- type 생략 -> 구조체 이름이 없다.
- 구조체 변수만 존재
- 주요 용도
- 마샬링, 언마샬링
- 테스트 작성
3.5.2 구조체 비교와 변환
- 구조체 비교는 항목에 따라 다름
- 두 개의 구조체가 같은 이름, 순서, 타입으로 구성되어 있으면 구조체 간에 타입 변환 가능