타입 통일 규칙
타입 통일 규칙
Go의 타입 추론이 "뭔가 알아서 잘 맞춰진다"고만 느끼셨다면, 그 뒤에는 이 규칙들이 조용히 일하고 있어요. 이번에는 두 타입이 언제, 어떻게 "통일(unify)"되는지 그 기준을 정리해 볼게요. 사실 평소에 코드를 작성할 때는 거의 신경 쓸 일이 없지만, 추론이 예상과 다르게 실패하는 희귀한 상황에서 왜 그랬는지 이해하는 데 아주 유용해요.
출처: Go Specification
본문
타입 통일 규칙(the type unification rules)은 두 타입이 통일되는지, 그리고 어떻게 통일되는지를 설명해요. 이 세부 사항은 Go 구현체에 실제로 영향을 주고, 에러 메시지의 구체적인 모습도 바꿔요(컴파일러가 타입 추론 에러를 보고하는지 다른 에러를 보고하는지 같은 차이요). 또 비정상적인 코드 상황에서 타입 추론이 왜 실패하는지도 설명해 줘요. 하지만 대체로 이런 규칙은 Go 코드를 쓸 때 무시해도 돼요. 타입 추론은 "예상대로 동작하도록" 설계되어 있고, 통일 규칙도 그에 맞춰 세밀하게 다듬어져 있거든요.
타입 통일은 **매칭 모드(matching mode)**에 의해 제어되는데, 이 모드는 정확(exact) 또는 느슨(loose) 둘 중 하나예요. 통일이 복합 타입 구조를 재귀적으로 내려갈 때, 타입의 요소들에 적용되는 **요소 매칭 모드(element matching mode)**는 매칭 모드와 동일하게 유지돼요. 단, 두 타입이 할당 가능성(assignability)을 위해 통일되는 경우(≡<sub>A</sub>)만 예외예요. 이때는 최상위 수준에서는 매칭 모드가 느슨하게 시작하지만, 요소 타입으로 내려가면 정확으로 바뀌어요. 타입이 같지 않아도 할당 가능할 수 있다는 사실을 반영한 거예요.
바인딩되지 않은 타입 파라미터가 아닌 두 타입은, 다음 조건 중 하나가 성립하면 정확히 통일돼요:
- 두 타입이 동일(identical)하다.
- 두 타입이 동일한 구조를 갖고, 그 요소 타입들이 정확히 통일된다.
- 정확히 하나의 타입이 바인딩되지 않은(unbound) 타입 파라미터이고, 그 타입 세트에 있는 모든 타입이
≡<sub>A</sub>에 대한 통일 규칙(최상위 수준에서는 느슨한 통일, 요소 타입에서는 정확한 통일)에 따라 다른 타입과 통일된다.
두 타입이 모두 바인딩된 타입 파라미터라면, 주어진 매칭 모드에 따라 다음과 같은 경우에 통일돼요:
- 두 타입 파라미터가 동일하다.
- 타입 파라미터 중 기껏해야 하나가 알려진 타입 인자를 갖고 있다. 이 경우 두 타입 파라미터는 *결합(joined)*되어, 둘 다 같은 타입 인자를 나타내게 돼요. 아직 어느 타입 파라미터도 알려진 타입 인자가 없다면, 나중에 그중 하나에 대해 추론된 타입 인자가 동시에 둘 모두에 대해 추론돼요.
- 두 타입 파라미터 모두 알려진 타입 인자를 갖고 있고, 그 타입 인자들이 주어진 매칭 모드에 따라 통일된다.
하나의 바인딩된 타입 파라미터 P와 또 다른 타입 T는 주어진 매칭 모드에 따라 다음 경우에 통일돼요:
P가 알려진 타입 인자를 갖고 있지 않다. 이 경우T가P의 타입 인자로 추론돼요.P가 알려진 타입 인자A를 갖고 있고,A와T가 주어진 매칭 모드에 따라 통일되며, 다음 조건 중 하나를 만족한다:A와T가 모두 인터페이스 타입이다: 이 경우A와T가 모두 정의된(defined) 타입이라면 반드시 동일(identical)해야 해요. 그렇지 않고 둘 중 어느 것도 정의된 타입이 아니라면, 같은 수의 메서드를 가져야 해요(A와T의 통일이 이미 메서드들이 일치한다는 것을 확립했거든요).A와T모두 인터페이스 타입이 아니다: 이 경우T가 정의된 타입이라면,T가A를 대신해P의 추론된 타입 인자가 돼요.
마지막으로, 바인딩되지 않은 타입 파라미터가 아닌 두 타입은 다음 경우에 느슨하게(그리고 요소 매칭 모드에 따라) 통일돼요:
- 두 타입이 정확히 통일된다.
- 한 타입은 정의된(defined) 타입이고, 다른 타입은 인터페이스가 아닌 타입 리터럴이며, 그 기본 타입(underlying types)이 요소 매칭 모드에 따라 통일된다.
- 두 타입 모두 동일한 타입 항(type terms)을 가진 인터페이스(타입 파라미터는 아님)이고, 둘 다 또는 둘 다 아니면 미리 선언된 타입 comparable을 임베드하며, 대응하는 메서드 타입들이 정확히 통일되고, 한 인터페이스의 메서드 세트가 다른 인터페이스의 메서드 세트의 부분 집합이다.
- 오직 한 타입만 인터페이스(타입 파라미터는 아님)이고, 두 타입의 대응하는 메서드들이 요소 매칭 모드에 따라 통일되며, 인터페이스의 메서드 세트가 다른 타입의 메서드 세트의 부분 집합이다.
- 두 타입이 동일한 구조를 갖고, 그 요소 타입들이 요소 매칭 모드에 따라 통일된다.