인덱스 표현식

인덱스 표현식 (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 타입이 부여돼요.
  • 인덱스 x0 <= 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에서 정말 자주 쓰이니, 직접 코드로 연습해 보세요.