기저 타입

기저 타입 (Underlying types)

Go에서 두 타입이 서로 '같은 타입'인지, 아니면 서로 호환되는 타입인지를 판단할 때 기준이 되는 개념이 있어요. 바로 underlying type이에요. 이 개념을 이해하면 stringA1이 왜 같은 타입 취급을 받는지, B1B2는 또 왜 그런지가 자연스럽게 보여요. 예시를 보면서 하나씩 따라가 볼게요.

출처: Go Specification

본문

모든 타입 T는 각자 자신만의 underlying type을 하나씩 갖고 있어요. 규칙은 의외로 단순해요. T가 미리 선언된(predeclared) boolean·numeric·string 타입 중 하나이거나 타입 리터럴(type literal)이라면, T의 underlying type은 바로 T 그 자체가 돼요. 그 외의 경우에는, T가 자기 선언에서 참조하는 타입의 underlying type이 곧 T의 underlying type이 되죠. 타입 파라미터(type parameter)의 경우에는 조금 달라요. 타입 파라미터의 underlying type은 자기 type constraint의 underlying type인데, 그 type constraint는 언제나 인터페이스(interface)예요.

type (
	A1 = string
	A2 = A1
)

type (
	B1 string
	B2 B1
	B3 []B1
	B4 B3
)

func f[P any](x P) { … }

코드 위쪽의 A1, A2string을 그대로 가리키는 별칭(alias)이에요. 그래서 string, A1, A2는 물론, 아래쪽에서 string으로 새로 정의한 B1B1을 가리키는 B2까지, 이 다섯 타입의 underlying type이 전부 string이 돼요. 한편 []B1은 리터럴이고, B3[]B1을, B4B3를 가리키죠. 그래서 []B1, B3, B4의 underlying type은 모두 []B1이에요. 마지막으로 제네릭 함수의 타입 파라미터 Pany로 제약을 걸었는데, anyinterface{}의 별칭이니 P의 underlying type은 interface{}가 돼요.

이렇게 정리하면, underlying type이 같다는 것이 곧 타입이 서로 호환 가능한지를 가늠하는 기준이 되어요. 이름이 서로 다른 타입처럼 보여도 underlying type이 같으면 서로 연결되는 타입들이라는 뜻이죠.

더 알아보기

  • Type identity — 두 타입이 '동일(identical)'한지, '다르다(different)'고 볼지는 어떻게 판단하는지 이어서 다뤄요.
  • Type definitions — 별칭(alias)과 새 타입 정의(new defined type)의 차이가 여기서 빛을 발해요.
  • Type constraints — 타입 파라미터의 underlying type이 결정되는 근거가 되는 제약 조건이에요.