슬라이스·맵·채널 만들기
슬라이스·맵·채널 만들기 (Making slices, maps and channels)
Go에서는 슬라이스·맵·채널을 일반적인 리터럴로는 만들기 어려워요. 길이가 몇인지, 버퍼를 얼마나 잡을지 같은 '크기'라는 개념이 따라붙기 때문인데요. 이때 쓰는 게 내장 함수 make예요. make는 타입 T(반드시 슬라이스·맵·채널 타입이거나 타입 파라미터)를 받고, 타입에 따라 정해진 표현식 목록을 추가로 받아요. 그리고 값으로는 타입 T의 값을 돌려줘요 — 포인터 *T가 아니라 값 그 자체죠. 메모리는 초기값(initial values) 섹션에서 설명한 대로 초기화돼요.
출처: Go Specification
본문
make가 타입별로 받는 인자를 표로 정리하면 이렇게 돼요.
Call Type T Result
make(T, n) slice slice of type T with length n and capacity n
make(T, n, m) slice slice of type T with length n and capacity m
make(T) map map of type T
make(T, n) map map of type T with initial space for approximately n elements
make(T) channel unbuffered channel of type T
make(T, n) channel buffered channel of type T, buffer size n
make(T, n) type parameter see below
make(T, n, m) type parameter see below
슬라이스는 n(길이)만 주면 길이와 용량이 모두 n이 되고, n, m 둘 다 주면 길이는 n, 용량은 m이 돼요. 맵은 크기 힌트 n을 받아 대략 n개의 원소를 담을 초기 공간을 잡고요, 채널은 버퍼 크기 n을 받아요. n이 없으면 버퍼가 없는(unbuffered) 채널이 됩니다.
첫 번째 인자가 타입 파라미터라면 조금 특별해요. 타입 집합(type set) 안의 모든 타입이 같은 기반 타입(바닥 타입)을 가져야 하는데, 그 기반 타입은 슬라이스나 맵 타입이어야 해요. 채널 타입이 섞여 있다면 채널 타입만 있어야 하고, 원소 타입이 모두 같아야 하며, 채널 방향이 서로 충돌하면 안 돼요.
크기 인자 n과 m은 각각 정수 타입이거나, 정수 타입만 담긴 타입 집합을 가지거나, 타입 없는(untyped) 상수여야 해요. 상수 크기 인자는 음수가 아니어야 하고, int 타입 값으로 표현 가능(representable)해야 하며, 타입 없는 상수라면 int 타입으로 취급돼요. n과 m이 모두 상수로 주어졌다면 n은 m보다 클 수 없어요. 슬라이스와 채널의 경우, 실행 시점(run time)에 n이 음수이거나 m보다 크면 런타임 패닉(run-time panic)이 발생해요.
s := make([]int, 10, 100) // slice with len(s) == 10, cap(s) == 100
s := make([]int, 1e3) // slice with len(s) == cap(s) == 1000
s := make([]int, 1<<63) // illegal: len(s) is not representable by a value of type int
s := make([]int, 10, 0) // illegal: len(s) > cap(s)
c := make(chan int, 10) // channel with a buffer size of 10
m := make(map[string]int, 100) // map with initial space for approximately 100 elements
make를 맵 타입에 크기 힌트 n과 함께 호출하면, n개의 맵 원소를 담을 초기 공간을 가진 맵이 만들어져요. 정확히 어느 정도의 공간을 잡는지는 구현에 따라 달라져요(implementation-dependent).