길이와 용량

길이와 용량 (Length and capacity)

슬라이스나 맵, 채널을 쓸 때면 빠지지 않고 등장하는 게 lencap이에요. 이 둘이 정확히 어떤 타입에서 뭘 돌려주는지, 또 언제 상수(constant)로 처리되는지 짚고 넘어갈게요.

출처: Go Specification

본문

내장 함수 lencap 은 여러 타입의 인자를 받아서 int 타입의 결과를 돌려줘요. 구현체는 이 결과가 항상 int에 들어맞는 크기임을 보장해요.

Call      Argument type    Result

len(s)    string type      string length in bytes
          [n]T, *[n]T      array length (== n)
          []T              slice length
          map[K]T          map length (number of defined keys)
          chan T           number of elements queued in channel buffer
          type parameter   see below

cap(s)    [n]T, *[n]T      array length (== n)
          []T              slice capacity
          chan T           channel buffer capacity
          type parameter   see below

만약 인자의 타입이 [Type parameter declarations](type parameter) P라면, len(e)(또는 그에 대응하는 cap(e)) 호출이 P의 타입 집합(type set)에 속한 각각의 타입에 대해 유효해야 해요. 결과는 PInstantiations될 때 함께 쓰인 타입 인자에 해당하는 타입을 가진 인자의 길이(또는 각각 용량)가 되는 거예요.

슬라이스의 용량(capacity)은 그 슬라이스가 자리 잡고 있는 기반 배열(underlying array)에 실제로 할당된 공간의 원소 수를 뜻해요. 그래서 어느 시점에든 다음 관계가 항상 성립해요:

0 <= len(s) <= cap(s)

nil 슬라이스나 nil 맵, nil 채널의 길이는 0이에요. nil 슬라이스나 nil 채널의 용량도 0이죠.

한 가지 헷갈리기 쉬운 부분이 있어요. len(s) 표현식은 s가 문자열 상수(string constant)일 때 상수예요. 또 s의 타입이 배열이거나 배열을 가리키는 포인터이고, 표현식 s가 [Receive operator](channel receives)나 (상수가 아닌) [Calls](function calls)를 포함하지 않는다면 len(s)cap(s) 모두 상수가 돼요 — 이 경우엔 s는 아예 평가(evaluate)되지 않아요. 그 외의 경우에는 lencap 호출은 상수가 아니고 s가 평가돼요.

아래 예시는 상수와 상수가 아닌 호출을 나란히 두고 비교해 둔 건데요. 주석만 따라가 봐도 각 줄이 왜 유효한지(혹은 왜 안 되는지) 바로 읽혀요.

const (
	c1 = imag(2i)                    // imag(2i) = 2.0 is a constant
	c2 = len([10]float64{2})         // [10]float64{2} contains no function calls
	c3 = len([10]float64{c1})        // [10]float64{c1} contains no function calls
	c4 = len([10]float64{imag(2i)})  // imag(2i) is a constant and no function call is issued
	c5 = len([10]float64{imag(z)})   // invalid: imag(z) is a (non-constant) function call
)
var z complex128

c5가 유효하지 않은 이유가 딱 궁금한 지점이죠. imag(z)z가 (상수가 아닌) 변수라서 함수 호출로 취급되거든요. 그래서 배열 안에 함수 호출이 들어가 버려서 len이 상수가 될 수 없어요.

더 알아보기