Перейти к основному содержимому
Модуль 6 · Урок 2 из 527/50 в курсе~10 min
Уроки модуля (2/5)

Тип утверждения

Утверждение типа извлекает конкретный тип из значения интерфейса. Он вам понадобится, если у вас есть interface{} (или «высокий» интерфейс) в рукой и необходимо рассматривать его как особый тип для доступа к полям или методы, отсутствующие в интерфейсе.

Синтаксис

Go
var i interface{} = "ciao"

s := i.(string)           // "panic" form: panics if it's not a string
s, ok := i.(string)       // "comma ok" form: ok = false if it's not a string

Две формы, две семантики:

ФормаУспехНеудача
v := i.(T)v = значение типа Tпаника во время выполнения
v, ok := i.(T)v=..., ok=truev = нулевое значение T, ok=false

Форма «Запятая ок»: самая безопасная

Go
var i interface{} = 42

if s, ok := i.(string); ok {
    fmt.Println("è stringa:", s)
} else {
    fmt.Println("non è stringa, ignoro")
}

ok позволяет без паники обрабатывать случаи «неправильного типа». Это идиоматический образец в подавляющем большинстве случаев.

Утверждение интерфейса

Утверждение работает не только с конкретными типами, но и с другими. интерфейсы:

Go
type Closer interface { Close() error }

func tryClose(x interface{}) {
    if c, ok := x.(Closer); ok {
        c.Close()
    }
}

Очень распространенный шаблон в стандартной библиотеке: «если мой ввод также io.Closer, в конце вызовите Close".

Утверждение об указателях и значениях

Утверждение должно ТОЧНО соответствовать динамическому типу:

Go
type Cat struct{}
func (c *Cat) Meow() {}

var a interface{} = &Cat{}

c1, ok := a.(*Cat)   // ok = true
c2, ok := a.(Cat)    // ok = false: it holds *Cat, not Cat

*Cat и Cat — это разные типы для системы типов.

Когда использовать утверждение или переключатель типа

  • Только 1 возможный тип, проверка «обнаружения функции» (например, приведение к дополнительному интерфейсу): утверждение типа с помощью comma ok.
  • 2+ возможных типа, распределение по нескольким ветвям: переключение типов (следующий урок).

Попробуйте это

Упражнение#go.m6.l2.e1
Попыток: 0Загрузка…

Используйте шаблон «запятая ок», чтобы извлечь строку из i.

Загрузка редактора…
Показать подсказку

Синтаксис: `v, ок := i.(T)`.

Решение доступно после 3 попыток

Упражнение#go.m6.l2.e2
Попыток: 0Загрузка…

Введите утверждение для int без запятой, ок (предположим, что я содержит int).

Загрузка редактора…
Показать подсказку

Без `ok` вы предполагаете, что тип определен; иначе паника.

Решение доступно после 3 попыток

Quiz#go.m6.l2.e3
Готово

Что произойдет с `s := i.(string)`, если i содержит int?

Go
var i interface{} = 42
s := i.(string)
Варианты ответа

Резюме

  • v := i.(T): паника, если динамический тип ≠ T.
  • v, ok := i.(T): безопасный шаблон, отметьте ok.
  • Работает также с другим интерфейсом («обнаружение функции»).
  • T и *T — это разные типы утверждения.
  • 1 тип → утверждение; 2+ типа → переключатель типа.