Совпадёт ли ветка type switch с case int, если динамический тип значения — отдельный именованный тип с базовым типом int?
Нет. Ветка case int не сработает: type switch сравнивает динамический тип значения с типом в case, а не только их базовые типы. Отдельный именованный тип считается другим типом, даже если он основан на int.
Интерфейсы в Go позволяют работать со значением через набор методов, не зная его конкретного типа. Однако в некоторых ситуациях программе нужно выбрать поведение именно по фактическому динамическому типу значения.
Для этого в языке предусмотрен type switch. Он сохраняет проверку типов явной и предсказуемой: ветка для конкретного типа срабатывает при точном совпадении динамического типа, а не при совпадении представления или базового типа.
Рассмотрим тип UserID, объявленный на основе int. Значение UserID(10) можно преобразовать в int, но это не делает его значением типа int автоматически.
Если ошибочно ожидать сопоставления по базовому типу, можно выбрать неверную ветку обработки или решить, что type switch выполняет неявное преобразование. Он этого не делает.
Динамический тип интерфейсного значения — это конкретный тип, которым было инициализировано значение внутри интерфейса. Для отдельного именованного типа UserID динамическим типом будет именно UserID, а не int.
Программа напечатает UserID. Чтобы получить ветку case int, значение нужно явно преобразовать к int до помещения в интерфейс или внутри соответствующей логики.
Важно отличать именованный тип от псевдонима. При объявлении псевдонима через type UserID = int это не новый тип: UserID и int обозначают один и тот же тип, поэтому case int совпадёт.
Если в case указан интерфейс, действует другое правило: ветка выбирается, когда динамический тип реализует этот интерфейс. Но для case с конкретным типом сравнение основано на идентичности типов, а не на совместимости по базовому типу.
В обработчик событий поступают значения типа any. Разработчик вводит type EventCode int и добавляет case int, рассчитывая обработать коды событий. В результате значения EventCode попадают не в эту ветку.
Можно преобразовывать все значения к int заранее, но это стирает различие между кодом события и обычным числом и может усложнить дальнейшую типобезопасную обработку. Можно добавить отдельный case EventCode; это сохраняет смысл именованного типа и делает обработку явной.
Выбор отдельной ветки case EventCode предпочтителен, если тип действительно выражает доменное понятие. Если различие между типами не нужно, проще использовать int без введения нового именованного типа.
case int, если значение сначала явно преобразовали из UserID в int?Да. После явного преобразования динамический тип помещённого в интерфейс результата будет int, поэтому ветка case int совпадёт. Type switch проверяет тип уже хранящегося значения и не анализирует, из какого типа оно ранее было преобразовано.
case interface{} со значением типа UserID?Да. Пустой интерфейс реализуется любым типом, включая UserID. В этом случае проверяется не идентичность конкретного типа UserID и интерфейса, а возможность динамического типа удовлетворить интерфейсному case.
UserID результат case int?Нет. Методы могут сделать UserID реализующим некоторый интерфейсный case, но не превращают его в int. Для конкретного case int типы по-прежнему различаются независимо от набора методов.