인덱스 표현식
인덱스 표현식 (Index expressions)
배열이나 슬라이스에서 특정 위치의 값을 꺼내야 할 때, 우리는 대괄호 [] 안에 위치를 넣어요. 그게 바로 인덱스 표현식이에요. Go에서는 배열, 배열을 가리키는 포인터, 슬라이스, 문자열, 맵에 모두 같은 문법 a[x]를 써서 요소에 접근할 수 있어요. 형태는 간단하지만, 타입마다 적용되는 규칙이 조금씩 달라서 이번에 하나씩 정리해 볼게요.
출처: Go Specification
본문
다음 형태의 기본 표현식(primary expression)은
a[x]
배열, 배열을 가리키는 포인터, 슬라이스, 문자열 또는 맵 a에서 인덱스 x에 해당하는 요소를 나타내요. 이때 값 x를 각각 인덱스(index) 또는 *맵 키(map key)*라고 불러요. 여기에 적용되는 규칙은 다음과 같아요.
a가 맵도 아니고 타입 매개변수도 아닐 때:
- 인덱스
x는 타입 없는 상수(untyped constant)여야 하거나, 그 타입이 정수 또는 타입 집합(type set)이 정수 타입만 포함하는 타입 매개변수여야 해요. - 상수 인덱스는 음수가 아니어야 하고,
int타입의 값으로 표현 가능해야 해요. - 타입이 없는 상수 인덱스에는
int타입이 부여돼요. - 인덱스
x는0 <= x < len(a)를 만족하면 *범위 안(in range)*에 있고, 그렇지 않으면 *범위 밖(out of range)*에 있어요.
a가 배열 타입 A일 때:
- 상수 인덱스는 반드시 범위 안에 있어야 해요.
- 실행 시간에
x가 범위 밖이면 런타임 패닉(run-time panic)이 발생해요. a[x]는 인덱스x위치의 배열 요소이고,a[x]의 타입은A의 요소 타입이에요.
a가 배열을 가리키는 포인터 타입일 때:
a[x]는(*a)[x]의 줄임 표현이에요.
a가 슬라이스 타입 S일 때:
- 실행 시간에
x가 범위 밖이면 런타임 패닉이 발생해요. a[x]는 인덱스x위치의 슬라이스 요소이고,a[x]의 타입은S의 요소 타입이에요.
a가 문자열 타입일 때:
- 문자열
a도 상수라면, 상수 인덱스는 반드시 범위 안에 있어야 해요. - 실행 시간에
x가 범위 밖이면 런타임 패닉이 발생해요. a[x]는 인덱스x위치의 상수가 아닌(non-constant) 바이트 값이고,a[x]의 타입은byte예요.a[x]에는 값을 할당할 수 없어요.
a가 맵 타입 M일 때:
x의 타입은M의 키 타입에 할당 가능(assignable)해야 해요.- 맵에 키
x를 가진 항목이 있으면,a[x]는 키x의 맵 요소이고a[x]의 타입은M의 요소 타입이에요. - 맵이
nil이거나 그런 항목을 포함하지 않으면,a[x]는M의 요소 타입에 대한 제로 값(zero value)이에요.
a가 타입 매개변수 타입 P일 때:
- 인덱스 표현식
a[x]는P의 타입 집합에 있는 모든 타입의 값에 대해 유효해야 해요. P의 타입 집합에 있는 모든 타입의 요소 타입은 서로 동일해야 해요. 이 맥락에서 문자열 타입의 요소 타입은byte예요.P의 타입 집합에 맵 타입이 있다면, 그 타입 집합의 모든 타입은 맵 타입이어야 하고, 각각의 키 타입도 모두 동일해야 해요.a[x]는P가 인스턴스화된 타입 인자(type argument)에서 인덱스x위치의 배열·슬라이스·문자열 요소, 또는 키x의 맵 요소이고,a[x]의 타입은 (동일한) 요소 타입이에요.P의 타입 집합이 문자열 타입을 포함하면a[x]에는 값을 할당할 수 없어요.
그 외의 경우 a[x]는 잘못된 표현이에요.
map[K]V 타입의 맵 a에 대한 인덱스 표현식이 다음 특별한 형태의 대입문(assignment statement)이나 초기화에서 쓰이면,
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
추가로 타입 없는 불리언 값 하나가 산출돼요. ok의 값은 키 x가 맵에 있으면 true, 그렇지 않으면 false예요.
nil 맵의 요소에 값을 할당하면 런타임 패닉이 발생해요.
더 알아보기
- 인덱스 외에도 슬라이스나 배열을 부분만 잘라내는 표현이 필요한데요, 그건 슬라이스 표현식(Slice expressions)에서 다뤄요.
- 인덱스 표현식의 입력이 되는 배열, 슬라이스, 문자열, 맵의 타입 자체가 궁금하다면 각각의 타입 절을 찾아보면 좋아요.
- 맵에서 키 존재 여부까지 한 번에 확인하는
v, ok := a[x]형태는 Go에서 정말 자주 쓰이니, 직접 코드로 연습해 보세요.