Уроки модуля (2/5)
Тип утверждения
Утверждение типа извлекает конкретный тип из значения интерфейса.
Он вам понадобится, если у вас есть interface{} (или «высокий» интерфейс) в
рукой и необходимо рассматривать его как особый тип для доступа к полям или
методы, отсутствующие в интерфейсе.
Синтаксис
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=true | v = нулевое значение T, ok=false |
Форма «Запятая ок»: самая безопасная
var i interface{} = 42
if s, ok := i.(string); ok {
fmt.Println("è stringa:", s)
} else {
fmt.Println("non è stringa, ignoro")
}ok позволяет без паники обрабатывать случаи «неправильного типа». Это
идиоматический образец в подавляющем большинстве случаев.
Утверждение интерфейса
Утверждение работает не только с конкретными типами, но и с другими. интерфейсы:
type Closer interface { Close() error }
func tryClose(x interface{}) {
if c, ok := x.(Closer); ok {
c.Close()
}
}Очень распространенный шаблон в стандартной библиотеке: «если мой ввод также
io.Closer, в конце вызовите Close".
Утверждение об указателях и значениях
Утверждение должно ТОЧНО соответствовать динамическому типу:
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+ возможных типа, распределение по нескольким ветвям: переключение типов (следующий урок).
Попробуйте это
Используйте шаблон «запятая ок», чтобы извлечь строку из i.
Показать подсказку
Синтаксис: `v, ок := i.(T)`.
Решение доступно после 3 попыток
Введите утверждение для int без запятой, ок (предположим, что я содержит int).
Показать подсказку
Без `ok` вы предполагаете, что тип определен; иначе паника.
Решение доступно после 3 попыток
Что произойдет с `s := i.(string)`, если i содержит int?
var i interface{} = 42
s := i.(string)Резюме
v := i.(T): паника, если динамический тип ≠ T.v, ok := i.(T): безопасный шаблон, отметьтеok.- Работает также с другим интерфейсом («обнаружение функции»).
Tи*T— это разные типы утверждения.- 1 тип → утверждение; 2+ типа → переключатель типа.